Es scheint, dass zwei oder mehr Threads aufgrund des Einflusses von GIL (Global Interpreter Lock) beim Threading nicht gleichzeitig parallel arbeiten. Thread of Python (CPython) (obwohl es parallel funktioniert). Dann habe ich mich gefragt, was mit anderen Implementierungen ist, also habe ich es mit Jython überprüft. Außerdem kann Jython die Java-API verwenden, daher habe ich auch java.lang.Thread überprüft.
Erstellen Sie einen Worker, der Aufgaben verteilt und berechnet, die Primzahlen im Bereich von 4 bis 100.000 auflisten. Das Folgende ist beim Threading. Thread wird verwendet.
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
Folgendes ist bei Verwendung von java.lang.Thread der Fall. (Nur die zu importierende Klasse ist unterschiedlich)
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
Der Vorgang des Tretens des Arbeiterfadens und des Messens der verstrichenen Zeit ist wie folgt.
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)
Die verstrichene Zeit bis zum Abschluss der Worker-Verarbeitung ist wie folgt.
Implementierung | Klasse | 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 kann jeweils nur einen Thread ausführen. Wenn Sie ihn also auf zwei Threads verteilen, wird er nicht schneller (eher langsamer), aber Jython liefert unterschiedliche Ergebnisse.
Da die verstrichene Zeit in einem Thread in Python und Jython fast gleich ist, wird sich die grundlegende Leistung für die diesmal verwendete Verarbeitung meiner Meinung nach nicht ändern. (Eigentlich hatte ich erwartet, dass Jython aufgrund der dynamischen Kompilierung von Java schneller sein würde.) Und im Fall von Jython wurden 2 Threads früher als 1 Thread beendet, sodass es sich anfühlt, als würden sie parallel arbeiten. Ich frage mich, ob die Operation hier implementierungsabhängig ist.
Recommended Posts