Il semble que threading.Thread of Python (CPython) ne fonctionne pas en parallèle avec deux ou plusieurs threads en même temps en raison de l'influence de GIL (Global Interpreter Lock) (bien qu'il fonctionne en parallèle). Ensuite, je me suis demandé ce qu'il en était des autres implémentations, alors je l'ai vérifié avec Jython. De plus, Jython peut utiliser l'API Java, j'ai donc vérifié java.lang.Thread également.
Créez un travailleur qui distribue et calcule des tâches qui énumèrent des nombres premiers compris entre 4 et 100 000. Ce qui suit est lorsque threading.Thread est utilisé.
py_worker.py
from threading import Thread
class Worker(Thread):
def __init__(self, start, end):
super(Worker, self).__init__()
self._start = start
self._end = end
def run(self):
self.prime_nums = []
for i in xrange(self._start, self._end):
if not 0 in self._remainders(i):
self.prime_nums.append(i)
def _remainders(self, end, start=2):
for i in xrange(start, end):
yield end % i
Ce qui suit concerne l'utilisation de java.lang.Thread. (Seule la classe à importer est différente)
jy_worker.py
from java.lang import Thread
class Worker(Thread):
def __init__(self, start, end):
super(Worker, self).__init__()
self._start = start
self._end = end
def run(self):
self.prime_nums = []
for i in xrange(self._start, self._end):
if not 0 in self._remainders(i):
self.prime_nums.append(i)
def _remainders(self, end, start=2):
for i in xrange(start, end):
yield end % i
Et le processus consistant à lancer le thread de travail et à mesurer le temps écoulé est le suivant.
main.py
import sys
from threading import Thread
from datetime import datetime
def total_seconds(td):
return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
if __name__ == '__main__':
argv = sys.argv
argc = len(argv)
if argc < 4:
print 'ERROR: <worker_module> <n_workers> <max_value>'
sys.exit(1)
worker_module = argv[1]
n_workers = int(argv[2])
max_value = int(argv[3])
min_value = 4
interval = (max_value - min_value) / n_workers
Worker = __import__(worker_module).Worker
workers = []
for start in xrange(4, max_value, interval):
print 'Worker: %s, %s' % (start, start+interval)
worker = Worker(start, start+interval)
workers.append(worker)
start_time = datetime.utcnow()
for worker in workers:
worker.start()
for worker in workers:
worker.join()
end_time = datetime.utcnow()
elapsed_time = end_time - start_time
elapsed_sec = total_seconds(elapsed_time)
n_primes = sum([len(w.prime_nums) for w in workers])
print '# of primes = %s, time = %s sec' % (n_primes, elapsed_sec)
Le temps écoulé jusqu'à ce que le traitement de travail soit terminé est le suivant.
la mise en oeuvre | classe | 1 thread | 2 threads |
---|---|---|---|
Python | threading.Thread | 100 sec | 125 sec |
Jython | threading.Thread | 101 sec | 73 sec |
Jython | java.lang.Thread | 101 sec | 77 sec |
Python ne peut exécuter qu'un seul thread à la fois, donc le distribuer sur deux threads ne le rend pas plus rapide (plutôt plus lent), mais Jython donne des résultats différents.
Étant donné que le temps écoulé dans un thread est presque le même en Python et Jython, je pense que les performances de base du traitement utilisé cette fois ne changeront pas. (En fait, je m'attendais à ce que Jython soit plus rapide grâce à la compilation dynamique de Java.) Et dans le cas de Jython, 2 threads se sont terminés avant 1 thread, donc on a l'impression qu'ils fonctionnent en parallèle. Je me demande si l'opération ici dépend de la mise en œuvre.
Recommended Posts