2009-02-14 1 views
6

J'essaye d'exécuter 500 clients qui envoient une requête au serveur simultanément à des fins de test de charge. Le client est à nouveau un programme ruby. Cela semble trivial. Mais je suis confronté à un problème étrange avec des fils de rubis. Mon code ressemble à ceci -Ruby ne crée que 3 threads à la fois

n = 10 

n.times do 
    Thread.new do 
    `calc` 
    end 
end 

Le code est un échantillon. J'essaie juste d'exécuter la commande calc à partir de la ligne de commande (Si vous essayez ce code sur une plate-forme autre que Windows, remplacez-le par une commande qui fonctionne sur votre ligne de commande ou votre shell). Ce sera plus tard remplacé par «ruby my_client.rb» et aussi la valeur de n sera fixée à 500 (ou autre).

Le problème que je suis confronté ici est que, quel que soit le nombre de threads que je veux créer, seuls les threads sont créés à la fois. C'est seulement 3 fenêtres calc sont ouvertes simultanément. Les threads restants attendent dans une file d'attente en attente de la fin de ces 3 threads. Peut-être que cela a quelque chose à voir avec les appels bloquants et non bloquants. Mais j'ai essayé Java-équivalent du même programme et cela a fonctionné parfaitement. C'est un vieux dicton que les discussions en rubis ne sont pas recommandées. Est-il vrai que c'est un problème avec les discussions de Ruby ou est-ce que je fais quelque chose de mal?

+0

Fonctionne pour moi bien, 1.8.7.72-2 sur Debian GNU/Linux. Je pense qu'il y a quelque chose de spécifique à Windows qui se passe. – womble

+0

Cest possible, mais le programme Java a parfaitement fonctionné sur la même plate-forme, la même machine. – Chirantan

+0

A bien fonctionné pour moi en utilisant ruby ​​1.8.7 sous Windows XP SP3. – Lolindrath

Répondre

3

L'implémentation C "Matz" de Ruby (MRI) n'utilise pas les threads natifs jusqu'à 1.8.6. Je crois que cela est changé dans Ruby 1.9, mais je comprends que nous n'allons probablement pas voir de bonnes performances multi-threads grâce au Global Interpreter Lock.

Si vous avez vraiment besoin d'un bon support multi-thread, et que votre logiciel doit être écrit en Ruby, vous pouvez essayer de l'exécuter sur JRuby. Un rapide test de santé mentale a montré que, en utilisant votre exemple, j'obtiendrais 2 threads OS sur MRI et 12 lors de l'exécution de la même chose sous JRuby. C'était sur OS X en utilisant "MRI" 1.8.6 et JRuby 1.1.6.

Une autre option, car il semble que vous générez un thread afin de forger un nouveau processus, pourrait être d'utiliser DRB à la place.

+0

Merci pour le pointeur DRb. Jruby devrait résoudre le problème. Vous n'avez aucune expérience en DRB, vous apprendrez et vous en tirerez aussi. Merci :) – Chirantan

+0

Juste parce que Ruby est seulement des fils verts, ne signifie pas qu'il devrait seulement exécuter trois threads à la fois. – womble

+0

Cela ressemble à une raison de toute façon – vava

0

Cela a fonctionné parfaitement pour moi sur os x avec textmate.

n = 10 

threads = [] 
n.times do |i| 
    threads << Thread.new do 
    `mate test#{i}.txt` 
    end 
end 

threads.each { |t| t.join } 
+0

Essayé votre code. Même problème. Peut être ce qu'Alex dit est juste. – Chirantan

4

Le problème que vous observez est spécifique aux applications GUI. Cela devient beaucoup mieux lorsque vous exécutez des éléments de ligne de commande à l'intérieur des travailleurs. Avec l'exemple ci-dessous, je peux très bien exécuter 200 instances wget, ce qui est probablement suffisant pour vos objectifs de test de charge.

n = 200 

threads = [] 
(1..n).each do |i| 
    threads << Thread.new do 
    puts `wget google.com` # forgive me google 
    sleep 10 
    puts "#{i} done" 
    end 
end 

threads.each do |t| # wait until all workers are done 
    t.join 
end 

Vous pourriez probablement obtenir beaucoup plus de travailleurs si vous passez du code wget au code Ruby pour aller chercher des pages Web. Et encore, vous devriez vous rappeler que les fils de Ruby ne sont échelonnés que très loin. Ne vous attendez pas à ce que plusieurs milliers ou threads parallèles fonctionnent correctement - essayez plutôt les sous-processus ou l'approche basée sur la continuité.

+0

Je ai le code sous Windows XP SP3, ruby ​​1.8.7 et cela a très bien fonctionné. – Lolindrath

0

Vous pouvez générer des processus distincts à la place. Kernel::fork ne fonctionne pas sous Windows, donc vous devrez utiliser le bon vieux Kernel::system ou Kernel::popen et créer un script séparé pour cela ou utiliser des arguments de ligne de commande spéciaux.

Même si Ruby 1.9 est presque là et si vous pouvez l'activer, il a des threads natifs du système d'exploitation et ce genre de choses ne se produirait pas.