Question

Sur mon application Ruby on Rails, je dois exécuter 50 tâches en arrière-plan en parallèle. Chaque travail crée une connexion TCP avec un serveur différent, fecth certaines données et met à jour un objet d’enregistrement actif.

Je connais différentes solutions pour effectuer cette tâche, mais aucune d’elles en parallèle. Delay_job (DJ), par exemple, pourrait être une excellente solution si seulement il pouvait exécuter tous les travaux en parallèle.

Des idées? Merci.

Était-ce utile?

La solution

Quelques pensées ...

  • Ce n'est pas parce que vous avez besoin de lire 50 sites et que vous souhaitez naturellement travailler en parallèle que vous avez besoin de 50 processus ou threads. Vous devez équilibrer le ralentissement et les frais généraux. Que diriez-vous d'avoir 10 ou 20 processus lisant chacun quelques sites?

  • Selon le Ruby que vous utilisez, faites attention aux fils verts, vous risquez de ne pas obtenir le résultat parallèle souhaité

  • Vous pouvez le structurer comme un inetd inverse côté client et utiliser connect_nonblock et IO.select pour obtenir les connexions parallèles souhaitées. faire en sorte que tous les serveurs répondent en parallèle. Vous n'avez pas vraiment besoin d'un traitement parallèle des résultats, vous avez juste besoin de vous mettre en ligne sur tous les serveurs en parallèle, car c'est là que se trouve vraiment la latence.

Donc, quelque chose comme ça de la bibliothèque de sockets ... étendez-le pour plusieurs connexions en suspens ...

require 'socket'
include Socket::Constants
socket = Socket.new(AF_INET, SOCK_STREAM, 0)
sockaddr = Socket.sockaddr_in(80, 'www.google.com')
begin
  socket.connect_nonblock(sockaddr)
  rescue Errno::EINPROGRESS
  IO.select(nil, [socket])
  begin
    socket.connect_nonblock(sockaddr)
    rescue Errno::EISCONN
  end
end
socket.write("GET / HTTP/1.0\r\n\r\n")
# here perhaps insert IO.select. You may not need multiple threads OR multiple
# processes with this technique, but if you do insert them here
results = socket.read

Autres conseils

Il est en fait possible d’exécuter plusieurs travailleurs retardés.

De http://github.com/collectiveidea/delayed_job :

# Runs two workers in separate processes.
$ RAILS_ENV=production script/delayed_job -n 2 start
$ RAILS_ENV=production script/delayed_job stop

Donc, en théorie, vous pouvez simplement exécuter:

$ RAILS_ENV=production script/delayed_job -n 50 start

Cela engendrera 50 processus, mais je ne suis pas sûr que ce soit recommandé en fonction des ressources du système sur lequel vous exécutez cette opération.

Une autre possibilité serait d'utiliser les discussions . Créez simplement un nouveau fil pour chacune de vos tâches.

Une chose à garder à l'esprit avec cette méthode est que ActiveRecord n'est pas thread-safe. Vous pouvez le rendre thread-safe en utilisant le paramètre suivant:

ActiveRecord::Base.allow_concurrency = true

Puisque vous travaillez avec des rails, je vous conseillerais d’utiliser delay_job pour cela plutôt que de vous séparer en threads ou en fourches. Raison d'être - traiter avec des délais d'attente et des trucs lorsque le navigateur est en attente peut être une vraie douleur. Il y a deux approches que vous pouvez adopter avec DJ

Le premier est - engendre plus de 50 travailleurs. En fonction de votre environnement, cela peut constituer une solution assez lourde en mémoire, mais cela fonctionne très bien. Ensuite, lorsque vous devez exécuter votre travail, assurez-vous simplement de créer 50 emplois uniques. Si vous avez trop de mémoire en réserve et que vous souhaitez procéder de la sorte, créez un environnement séparé, spécialement pour vos employés.

La deuxième méthode consiste à créer un travail unique utilisant Curl :: Multi pour exécuter vos 50 requêtes TCP simultanées. Vous pouvez en savoir plus à ce sujet ici: http://curl-multi.rubyforge.org/ De cette manière, vous pourriez avoir un processeur d’arrière-plan exécutant toutes vos demandes TCP en parallèle.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top