Pregunta

Estoy tratando de descargar más de 1 millón de páginas (URLs que terminan por una secuencia ID). He implementado tipo de usos múltiples gestor de descargas con número configurable de descarga hilos y un hilo de procesamiento. Los archivos de descargas descargador en lotes:

curl = Curl::Easy.new

batch_urls.each { |url_info|
    curl.url = url_info[:url]
    curl.perform
    file = File.new(url_info[:file], "wb")
    file << curl.body_str
    file.close
    # ... some other stuff
}

He tratado de descarga 8.000 páginas de muestra. Cuando se utiliza el código anterior, me sale 1000 en 2 minutos. Cuando escribo todas las direcciones URL en un archivo y hacer en la shell:

cat list | xargs curl

I gen todas las 8000 páginas en dos minutos.

La cosa es que necesito que tenga en código rubí, porque no hay otra monitoreo y procesamiento de código.

He intentado:

  • Curl :: Multi - de alguna manera es más rápido, pero no alcanza 50-90% de los archivos (no descarga ellos y da ninguna razón / código)
  • múltiples hilos con el enrollamiento :: Fácil - alrededor de la misma velocidad que un solo subproceso

¿Por qué se reutiliza Curl :: Fácil más lenta que la línea de comandos posteriores llamadas enrollamiento y cómo puedo hacerlo más rápido? O lo que estoy haciendo mal?

Yo preferiría arreglar mi código del gestor de descarga que para hacer la descarga para este caso de una manera diferente.

Antes de esto, yo estaba llamando wget de línea de comandos, que he proporcionado con un archivo con la lista de direcciones URL. Howerver, no se manejaron todos los errores, también que no era posible especificar el archivo de salida para cada URL por separado cuando se utiliza la lista de URL.

Ahora me parece que la mejor manera sería utilizar múltiples hilos con llamada al sistema de comando 'rizo'. Pero ¿por qué cuando puedo usar directamente Curl en Ruby?

Código para el gestor de descargas es aquí, si que podría ayudar: Descargar Manager (he jugado con los tiempos de espera, de no-ajustarlo a diferentes valores, no parecía ayuda)

Alguna pista apreciado.

¿Fue útil?

Solución

Esto podría ser una tarea ajuste para Typhoeus

Algo como esto (no probado):

require 'typhoeus'

def write_file(filename, data)
    file = File.new(filename, "wb")
    file.write(data)
    file.close
      # ... some other stuff
end

hydra = Typhoeus::Hydra.new(:max_concurrency => 20)

batch_urls.each do |url_info|
    req = Typhoeus::Request.new(url_info[:url])
    req.on_complete do |response|
      write_file(url_info[:file], response.body)
    end
    hydra.queue req
end

hydra.run

Ahora que lo pienso de ella, es posible obtener un problema de memoria debido a la enorme cantidad que de archivos. Una forma de prevenir que sería la de no almacenar los datos en una variable, sino que transmitir al archivo directamente. Se podría usar em-petición http para eso.

EventMachine.run {
  http = EventMachine::HttpRequest.new('http://www.website.com/').get
  http.stream { |chunk| print chunk }
  # ...
}

Otros consejos

Por lo tanto, si no se establece un manejador on_body de acera amortiguará la descarga. Si está descargando archivos que debe utilizar un controlador on_body. Si quiere descargar varios archivos usando Rubí Curl, pruebe la interfaz Curl :: Multi.download.

require 'rubygems'
require 'curb'

urls_to_download = [
  'http://www.google.com/',
  'http://www.yahoo.com/',
  'http://www.cnn.com/',
  'http://www.espn.com/'
]
path_to_files = [
  'google.com.html',
  'yahoo.com.html',
  'cnn.com.html',
  'espn.com.html'
]

Curl::Multi.download(urls_to_download, {:follow_location => true}, {}, path_to_files) {|c,p|}

Si desea sólo tiene que descargar un solo archivo.

Curl::Easy.download('http://www.yahoo.com/')

Aquí es un recurso bueno: http://gist.github.com/405779

Ha habido puntos de referencia que se ha hecho en comparación con otros métodos de acera como HTTPClient. El ganador, en casi todas las categorías fue HTTPClient. Además, ha habido algunos casos documentados en los que bordillo no funciona en escenarios multi-threading.

Al igual que usted, he tenido su experiencia. Me encontré con los comandos del sistema de enrollamiento en más de 20 hilos concurrentes y que era 10 ayunantes X que correr bordillo en más de 20 hilos concurrentes. No importa, lo he intentado, esto fue siempre el caso.

he desde entonces pasó a HTTPClient, y la diferencia es enorme. Ahora corre tan rápido como 20 comandos simultáneos del sistema rizo, y utiliza menos CPU también.

En primer lugar permítanme decir que no sé casi nada sobre Ruby.

Lo que sí sé es que Ruby es un lenguaje interpretado; no es sorprendente que es más lento que el código muy optimizado que ha sido compilado para una plataforma específica. Cada operación de archivo, probablemente tendrá cheques alrededor que curl no lo hace. El "otras cosas" se ralentizar las cosas aún más.

¿Usted ha intentado perfil de su código para ver donde la mayor parte del tiempo se gasta?

Stiivi,

Net :: HTTP bastaría para simples la descarga de páginas HTML?

No se especificó una versión de Ruby, pero las discusiones en 1.8.x son hilos de espacio de usuario, no programadas por el sistema operativo, por lo que toda la intérprete de Ruby sólo utilizan cada vez una CPU / núcleo. Además de eso hay un intérprete de bloqueo global, y probablemente otras cerraduras, así, lo que interfiere con la concurrencia. Puesto que usted está tratando de maximizar el rendimiento de la red, es probable que subutilizar CPU.

freza tantos procesos como la máquina tiene memoria para, y limitar la dependencia de los hilos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top