J'essaie de comprendre le threading en Python. J'ai consulté la documentation et les exemples, mais franchement, de nombreux exemples sont trop sophistiqués et j'ai du mal à les comprendre.
Comment montrez-vous clairement les tâches divisées pour le multi-threading?
Depuis que cette question a été posée en 2010, il existe une réelle simplification sur la manière de faire du multithreading simple avec python avec map et pool.
Le code ci-dessous provient d'un article/blog que vous devriez absolument consulter (aucune affiliation) - Parallélisme sur une seule ligne: un meilleur modèle pour les tâches de threading quotidiennes = = . Je vais résumer ci-dessous - cela finit par ne comporter que quelques lignes de code:
from multiprocessing.dummy import Pool as ThreadPool
pool = ThreadPool(4)
results = pool.map(my_function, my_array)
Quelle est la version multithread de:
results = []
for item in my_array:
results.append(my_function(item))
Description
Map est une petite fonction sympa, et la clé pour injecter facilement du parallélisme dans votre code Python. Pour ceux qui ne sont pas familiers, la carte est quelque chose qui provient des langages fonctionnels comme LISP. C'est une fonction qui mappe une autre fonction sur une séquence.
Map gère l'itération sur la séquence pour nous, applique la fonction et stocke tous les résultats dans une liste pratique à la fin.
Mise en oeuvre
Les versions parallèles de la fonction map sont fournies par deux bibliothèques: le multitraitement, ainsi que son enfant-mère peu connu, mais tout aussi fantastique: le multiprocessing.dummy.
multiprocessing.dummy
est exactement identique au module de multitraitement, mais utilise des threads à la place (ne distinction importante - utilise plusieurs processus pour une utilisation intensive du processeur tâches; threads pour (et pendant IO ):
multiprocessing.dummy réplique l'API de multitraitement mais n'est qu'un encapsuleur autour du module de threading.
import urllib2
from multiprocessing.dummy import Pool as ThreadPool
urls = [
'http://www.python.org',
'http://www.python.org/about/',
'http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html',
'http://www.python.org/doc/',
'http://www.python.org/download/',
'http://www.python.org/getit/',
'http://www.python.org/community/',
'https://wiki.python.org/moin/',
]
# make the Pool of workers
pool = ThreadPool(4)
# open the urls in their own threads
# and return the results
results = pool.map(urllib2.urlopen, urls)
# close the pool and wait for the work to finish
pool.close()
pool.join()
Et les résultats de chronométrage:
Single thread: 14.4 seconds
4 Pool: 3.1 seconds
8 Pool: 1.4 seconds
13 Pool: 1.3 seconds
Passer plusieurs arguments (fonctionne comme ceci niquement dans Python 3.3 et versions ultérieures ):
Pour passer plusieurs tableaux:
results = pool.starmap(function, Zip(list_a, list_b))
ou pour passer une constante et un tableau:
results = pool.starmap(function, Zip(itertools.repeat(constant), list_a))
Si vous utilisez une version antérieure de Python, vous pouvez transmettre plusieurs arguments via cette solution de contournement .
(Merci à ser136036 pour le commentaire utile)
Voici un exemple simple: vous devez essayer quelques URL alternatives et renvoyer le contenu de la première à répondre.
import Queue
import threading
import urllib2
# called by each thread
def get_url(q, url):
q.put(urllib2.urlopen(url).read())
theurls = ["http://google.com", "http://yahoo.com"]
q = Queue.Queue()
for u in theurls:
t = threading.Thread(target=get_url, args = (q,u))
t.daemon = True
t.start()
s = q.get()
print s
Dans ce cas, le threading est utilisé comme une optimisation simple: chaque sous-thread attend une URL à résoudre et à répondre, afin de mettre son contenu dans la file d'attente; chaque thread est un démon (ne gardera pas le processus en place si le thread principal se termine - c'est plus courant qu'autrement); le fil principal démarre tous les sous-thèmes, effectue une get
sur la file d'attente jusqu'à ce que l'un d'entre eux ait effectué un put
, puis émet le résultat et se termine (ce qui supprime les sous-threads en cours d'exécution, car ce sont des fils de démons).
L'utilisation correcte des threads dans Python est invariablement connectée aux opérations d'E/S (CPython n'utilisant pas plusieurs cœurs pour exécuter des tâches liées au processeur, la seule raison de ce thread est de ne pas bloquer le processus, mais attendez quelques I/O). Les files d’attente sont presque toujours le meilleur moyen de confier du travail aux threads et/ou de collecter les résultats du travail, soit dit en passant, et ils sont intrinsèquement sécuritaires pour vous éviter de vous inquiéter des verrous, des conditions, des événements, des sémaphores et autres. thread concepts de coordination/communication.
REMARQUE: Pour la parallélisation réelle en Python, vous devez utiliser le module multitraitement pour créer plusieurs processus qui s'exécutent en parallèle (en raison du verrou d'interpréteur global, les threads Python fournissent un entrelacement mais sont en réalité exécutés en série, pas en parallèle, et ne sont utiles que pour l’entrelacement des opérations d’E/S).
Toutefois, si vous recherchez simplement un entrelacement (ou effectuez des opérations d’E/S pouvant être parallélisées malgré le verrou d’interpréteur global), le module threading est le point de départ idéal. Comme exemple très simple, considérons le problème de la somme d’une plage étendue en sommant des sous-plages en parallèle:
import threading
class SummingThread(threading.Thread):
def __init__(self,low,high):
super(SummingThread, self).__init__()
self.low=low
self.high=high
self.total=0
def run(self):
for i in range(self.low,self.high):
self.total+=i
thread1 = SummingThread(0,500000)
thread2 = SummingThread(500000,1000000)
thread1.start() # This actually causes the thread to run
thread2.start()
thread1.join() # This waits until the thread has completed
thread2.join()
# At this point, both threads have completed
result = thread1.total + thread2.total
print result
Notez que ce qui précède est un exemple très stupide, car il ne fait absolument aucune entrée/sortie et sera exécuté en série bien que entrelacé (avec la surcharge de la commutation de contexte) dans CPython en raison du verrou d'interprète global.
Comme d’autres, CPython ne peut utiliser les threads que pour les attentes I\O en raison de GIL. Si vous souhaitez bénéficier de plusieurs cœurs pour les tâches liées à la CPU, utilisez multitraitement :
from multiprocessing import Process
def f(name):
print 'hello', name
if __== '__main__':
p = Process(target=f, args=('bob',))
p.start()
p.join()
Juste une note, la file d'attente n'est pas requise pour les threads.
C’est l’exemple le plus simple que je puisse imaginer et qui montre 10 processus exécutés simultanément.
import threading
from random import randint
from time import sleep
def print_number(number):
# Sleeps a random 1 to 10 seconds
Rand_int_var = randint(1, 10)
sleep(Rand_int_var)
print "Thread " + str(number) + " slept for " + str(Rand_int_var) + " seconds"
thread_list = []
for i in range(1, 10):
# Instantiates the thread
# (i) does not make a sequence, so (i,)
t = threading.Thread(target=print_number, args=(i,))
# Sticks the thread in a list so that it remains accessible
thread_list.append(t)
# Starts threads
for thread in thread_list:
thread.start()
# This blocks the calling thread until the thread whose join() method is called is terminated.
# From http://docs.python.org/2/library/threading.html#thread-objects
for thread in thread_list:
thread.join()
# Demonstrates that the main process waited for threads to complete
print "Done"
La réponse d’Alex Martelli m’a aidé, mais voici une version modifiée que j’ai trouvée plus utile (du moins pour moi).
Mise à jour: fonctionne à la fois en python2 et en python3
try:
# for python3
import queue
from urllib.request import urlopen
except:
# for python2
import Queue as queue
from urllib2 import urlopen
import threading
worker_data = ['http://google.com', 'http://yahoo.com', 'http://bing.com']
#load up a queue with your data, this will handle locking
q = queue.Queue()
for url in worker_data:
q.put(url)
#define a worker function
def worker(url_queue):
queue_full = True
while queue_full:
try:
#get your data off the queue, and do some work
url = url_queue.get(False)
data = urlopen(url).read()
print(len(data))
except queue.Empty:
queue_full = False
#create as many threads as you want
thread_count = 5
for i in range(thread_count):
t = threading.Thread(target=worker, args = (q,))
t.start()
J'ai trouvé cela très utile: créez autant de threads que de cœurs et laissez-les exécuter un grand nombre de tâches (dans ce cas, appeler un programme Shell):
import Queue
import threading
import multiprocessing
import subprocess
q = Queue.Queue()
for i in range(30): #put 30 tasks in the queue
q.put(i)
def worker():
while True:
item = q.get()
#execute a task: call a Shell program and wait until it completes
subprocess.call("echo "+str(item), Shell=True)
q.task_done()
cpus=multiprocessing.cpu_count() #detect number of cores
print("Creating %d threads" % cpus)
for i in range(cpus):
t = threading.Thread(target=worker)
t.daemon = True
t.start()
q.join() #block until all tasks are done
Étant donné une fonction, f
, enfilez-la comme ceci:
import threading
threading.Thread(target=f).start()
Pour passer des arguments à f
threading.Thread(target=f, args=(a,b,c)).start()
Python 3 a la facilité de Lancer des tâches parallèles . Cela facilite notre travail.
Il a pour pool de threads et pool de processus .
Ce qui suit donne un aperçu:
Exemple de ThreadPoolExecutor
import concurrent.futures
import urllib.request
URLS = ['http://www.foxnews.com/',
'http://www.cnn.com/',
'http://europe.wsj.com/',
'http://www.bbc.co.uk/',
'http://some-made-up-domain.com/']
# Retrieve a single page and report the URL and contents
def load_url(url, timeout):
with urllib.request.urlopen(url, timeout=timeout) as conn:
return conn.read()
# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
# Start the load operations and mark each future with its URL
future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}
for future in concurrent.futures.as_completed(future_to_url):
url = future_to_url[future]
try:
data = future.result()
except Exception as exc:
print('%r generated an exception: %s' % (url, exc))
else:
print('%r page is %d bytes' % (url, len(data)))
ProcessPoolExecutor
import concurrent.futures
import math
PRIMES = [
112272535095293,
112582705942171,
112272535095293,
115280095190773,
115797848077099,
1099726899285419]
def is_prime(n):
if n % 2 == 0:
return False
sqrt_n = int(math.floor(math.sqrt(n)))
for i in range(3, sqrt_n + 1, 2):
if n % i == 0:
return False
return True
def main():
with concurrent.futures.ProcessPoolExecutor() as executor:
for number, prime in Zip(PRIMES, executor.map(is_prime, PRIMES)):
print('%d is prime: %s' % (number, prime))
if __== '__main__':
main()
Pour moi, l'exemple parfait pour le threading est la surveillance des événements asynchrones. Regardez ce code.
# thread_test.py
import threading
import time
class Monitor(threading.Thread):
def __init__(self, mon):
threading.Thread.__init__(self)
self.mon = mon
def run(self):
while True:
if self.mon[0] == 2:
print "Mon = 2"
self.mon[0] = 3;
Vous pouvez jouer avec ce code en ouvrant une session IPython et en effectuant quelque chose comme:
>>>from thread_test import Monitor
>>>a = [0]
>>>mon = Monitor(a)
>>>mon.start()
>>>a[0] = 2
Mon = 2
>>>a[0] = 2
Mon = 2
Attends quelques minutes
>>>a[0] = 2
Mon = 2
Utilisation du nouveau module flamboyant concurrent.futures
def sqr(val):
import time
time.sleep(0.1)
return val * val
def process_result(result):
print(result)
def process_these_asap(tasks):
import concurrent.futures
with concurrent.futures.ProcessPoolExecutor() as executor:
futures = []
for task in tasks:
futures.append(executor.submit(sqr, task))
for future in concurrent.futures.as_completed(futures):
process_result(future.result())
# Or instead of all this just do:
# results = executor.map(sqr, tasks)
# list(map(process_result, results))
def main():
tasks = list(range(10))
print('Processing {} tasks'.format(len(tasks)))
process_these_asap(tasks)
print('Done')
return 0
if __== '__main__':
import sys
sys.exit(main())
L’approche de l’exécuteur peut sembler familière à tous ceux qui se sont déjà familiarisés avec Java auparavant.
Remarque supplémentaire: pour préserver la santé de l'univers, n'oubliez pas de fermer vos pools/exécuteurs si vous n'utilisez pas le contexte with
(ce qui est tellement génial qu'il le fait pour vous).
La plupart des documentations et des tutoriels utilisent les modules Threading
et Queue
de Python. Ils peuvent sembler accablants pour les débutants.
Considérez peut-être le module concurrent.futures.ThreadPoolExecutor
de python 3. Combiné à la clause with
et à la compréhension de la liste, il pourrait constituer un véritable charme.
from concurrent.futures import ThreadPoolExecutor, as_completed
def get_url(url):
# Your actual program here. Using threading.Lock() if necessary
return ""
# List of urls to fetch
urls = ["url1", "url2"]
with ThreadPoolExecutor(max_workers = 5) as executor:
# Create threads
futures = {executor.submit(get_url, url) for url in urls}
# as_completed() gives you the threads once finished
for f in as_completed(futures):
# Get the results
rs = f.result()
J'ai vu beaucoup d'exemples ici où aucun travail réel n'était effectué + ils étaient principalement liés au processeur. Voici un exemple de tâche liée à la CPU qui calcule tous les nombres premiers compris entre 10 millions et 10,05 millions. J'ai utilisé les 4 méthodes ici
import math
import timeit
import threading
import multiprocessing
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
def time_stuff(fn):
"""
Measure time of execution of a function
"""
def wrapper(*args, **kwargs):
t0 = timeit.default_timer()
fn(*args, **kwargs)
t1 = timeit.default_timer()
print("{} seconds".format(t1 - t0))
return wrapper
def find_primes_in(nmin, nmax):
"""
Compute a list of prime numbers between the given minimum and maximum arguments
"""
primes = []
#Loop from minimum to maximum
for current in range(nmin, nmax + 1):
#Take the square root of the current number
sqrt_n = int(math.sqrt(current))
found = False
#Check if the any number from 2 to the square root + 1 divides the current numnber under consideration
for number in range(2, sqrt_n + 1):
#If divisible we have found a factor, hence this is not a prime number, lets move to the next one
if current % number == 0:
found = True
break
#If not divisible, add this number to the list of primes that we have found so far
if not found:
primes.append(current)
#I am merely printing the length of the array containing all the primes but feel free to do what you want
print(len(primes))
@time_stuff
def sequential_prime_Finder(nmin, nmax):
"""
Use the main process and main thread to compute everything in this case
"""
find_primes_in(nmin, nmax)
@time_stuff
def threading_prime_Finder(nmin, nmax):
"""
If the minimum is 1000 and the maximum is 2000 and we have 4 workers
1000 - 1250 to worker 1
1250 - 1500 to worker 2
1500 - 1750 to worker 3
1750 - 2000 to worker 4
so lets split the min and max values according to the number of workers
"""
nrange = nmax - nmin
threads = []
for i in range(8):
start = int(nmin + i * nrange/8)
end = int(nmin + (i + 1) * nrange/8)
#Start the thrread with the min and max split up to compute
#Parallel computation will not work here due to GIL since this is a CPU bound task
t = threading.Thread(target = find_primes_in, args = (start, end))
threads.append(t)
t.start()
#Dont forget to wait for the threads to finish
for t in threads:
t.join()
@time_stuff
def processing_prime_Finder(nmin, nmax):
"""
Split the min, max interval similar to the threading method above but use processes this time
"""
nrange = nmax - nmin
processes = []
for i in range(8):
start = int(nmin + i * nrange/8)
end = int(nmin + (i + 1) * nrange/8)
p = multiprocessing.Process(target = find_primes_in, args = (start, end))
processes.append(p)
p.start()
for p in processes:
p.join()
@time_stuff
def thread_executor_prime_Finder(nmin, nmax):
"""
Split the min max interval similar to the threading method but use thread pool executor this time
This method is slightly faster than using pure threading as the pools manage threads more efficiently
This method is still slow due to the GIL limitations since we are doing a CPU bound task
"""
nrange = nmax - nmin
with ThreadPoolExecutor(max_workers = 8) as e:
for i in range(8):
start = int(nmin + i * nrange/8)
end = int(nmin + (i + 1) * nrange/8)
e.submit(find_primes_in, start, end)
@time_stuff
def process_executor_prime_Finder(nmin, nmax):
"""
Split the min max interval similar to the threading method but use the process pool executor
This is the fastest method recorded so far as it manages process efficiently + overcomes GIL limitations
RECOMMENDED METHOD FOR CPU BOUND TASKS
"""
nrange = nmax - nmin
with ProcessPoolExecutor(max_workers = 8) as e:
for i in range(8):
start = int(nmin + i * nrange/8)
end = int(nmin + (i + 1) * nrange/8)
e.submit(find_primes_in, start, end)
def main():
nmin = int(1e7)
nmax = int(1.05e7)
print("Sequential Prime Finder Starting")
sequential_prime_Finder(nmin, nmax)
print("Threading Prime Finder Starting")
threading_prime_Finder(nmin, nmax)
print("Processing Prime Finder Starting")
processing_prime_Finder(nmin, nmax)
print("Thread Executor Prime Finder Starting")
thread_executor_prime_Finder(nmin, nmax)
print("Process Executor Finder Starting")
process_executor_prime_Finder(nmin, nmax)
main()
Voici les résultats sur ma machine principale Mac OSX 4
Sequential Prime Finder Starting
9.708213827005238 seconds
Threading Prime Finder Starting
9.81836523200036 seconds
Processing Prime Finder Starting
3.2467174359990167 seconds
Thread Executor Prime Finder Starting
10.228896902000997 seconds
Process Executor Finder Starting
2.656402041000547 seconds
Voici l'exemple très simple d'importation CSV à l'aide de threads. [L’inclusion de la bibliothèque peut différer selon l’objet]
Fonctions d'assistance:
from threading import Thread
from project import app
import csv
def import_handler(csv_file_name):
thr = Thread(target=dump_async_csv_data, args=[csv_file_name])
thr.start()
def dump_async_csv_data(csv_file_name):
with app.app_context():
with open(csv_file_name) as File:
reader = csv.DictReader(File)
for row in reader:
#DB operation/query
Fonction du conducteur:
import_handler(csv_file_name)
Multi threading avec un exemple simple qui sera utile. Vous pouvez le lancer et comprendre facilement comment fonctionne le multi-thread en python. J'ai utilisé lock pour empêcher d'accéder à d'autres threads jusqu'à ce que les threads précédents aient terminé leur travail. Par l'utilisation de
tLock = threading.BoundedSemaphore (valeur = 4)
dans cette ligne de code, vous pouvez autoriser le nombre de processus à la fois tout en maintenant le reste du thread qui sera exécuté ultérieurement ou une fois les processus précédents terminés.
import threading
import time
#tLock = threading.Lock()
tLock = threading.BoundedSemaphore(value=4)
def timer(name, delay, repeat):
print "\r\nTimer: ", name, " Started"
tLock.acquire()
print "\r\n", name, " has the acquired the lock"
while repeat > 0:
time.sleep(delay)
print "\r\n", name, ": ", str(time.ctime(time.time()))
repeat -= 1
print "\r\n", name, " is releaseing the lock"
tLock.release()
print "\r\nTimer: ", name, " Completed"
def Main():
t1 = threading.Thread(target=timer, args=("Timer1", 2, 5))
t2 = threading.Thread(target=timer, args=("Timer2", 3, 5))
t3 = threading.Thread(target=timer, args=("Timer3", 4, 5))
t4 = threading.Thread(target=timer, args=("Timer4", 5, 5))
t5 = threading.Thread(target=timer, args=("Timer5", 0.1, 5))
t1.start()
t2.start()
t3.start()
t4.start()
t5.start()
print "\r\nMain Complete"
if __== "__main__":
Main()
Aucune des solutions ci-dessus n’utilisait réellement plusieurs cœurs sur mon serveur GNU/Linux (où je n’ai pas de droits d’administrateur). Ils ont juste couru sur un seul noyau. J'ai utilisé l'interface os.fork
de niveau inférieur pour générer plusieurs processus. C'est le code qui a fonctionné pour moi:
from os import fork
values = ['different', 'values', 'for', 'threads']
for i in range(len(values)):
p = fork()
if p == 0:
my_function(values[i])
break
import threading
import requests
def send():
r = requests.get('https://www.stackoverlow.com')
thread = []
t = threading.Thread(target=send())
thread.append(t)
t.start()
J'aimerais contribuer avec un exemple simple et les explications que j'ai trouvées utiles lorsque j'ai dû aborder ce problème moi-même.
Ici, je vais coller quelques informations utiles sur GIL et un exemple quotidien simple (en utilisant multiprocessing.dummy) et ses points de repère avec et sans multithreading.
verrouillage d'interprète global (GIL)
Python n'autorise pas le multi-threading dans le vrai sens du mot. Il contient un package multi-threading, mais si vous souhaitez utiliser plusieurs threads pour accélérer votre code, il est généralement déconseillé de l'utiliser. Python possède une construction appelée verrou d'interpréteur global (GIL). Le GIL veille à ce qu'un seul de vos "threads" puisse être exécuté à la fois. Un thread acquiert le GIL, fait un peu de travail, puis passe le GIL sur le prochain thread. Cela se produit très rapidement, alors, pour l’œil humain, il peut sembler que vos threads s’exécutent en parallèle, mais ils ne font que jouer à tour de rôle en utilisant le même cœur de processeur. Tout ce passage de GIL ajoute une surcharge à l'exécution. Cela signifie que si vous voulez que votre code soit exécuté plus rapidement, l'utilisation du package de threading n'est souvent pas une bonne idée.
Il y a des raisons d'utiliser le package de threading de Python. Si vous souhaitez gérer simultanément certaines tâches et que l'efficacité n'est pas un problème, c'est tout à fait correct et pratique. Ou si vous exécutez du code qui doit attendre quelque chose (comme un IO), alors cela peut avoir beaucoup de sens. Mais la bibliothèque de threads ne vous laissera pas utiliser de cœurs de processeur supplémentaires.
Le multi-threading peut être externalisé vers le système d'exploitation (en effectuant plusieurs traitements), une application externe appelant votre code Python (par exemple, Spark ou Hadoop), ou un code vos appels de code Python (par exemple: vous pourriez demander à votre code Python d'appeler une fonction C qui exécute les tâches onéreuses multi-threadées).
Pourquoi ça compte
Parce que beaucoup de gens passent beaucoup de temps à essayer de trouver des goulots d'étranglement dans leur fantaisie Python code multi-thread avant de savoir ce qu'est la GIL.
Une fois que cette information est claire, voici mon code:
#!/bin/python
from multiprocessing.dummy import Pool
from subprocess import PIPE,Popen
import time
import os
# In the variable pool_size we define the "parallelness".
# For CPU-bound tasks, it doesn't make sense to create more Pool processes
# than you have cores to run them on.
#
# On the other hand, if you are using I/O-bound tasks, it may make sense
# to create a quite a few more Pool processes than cores, since the processes
# will probably spend most their time blocked (waiting for I/O to complete).
pool_size = 8
def do_ping(ip):
if os.name == 'nt':
print ("Using Windows Ping to " + ip)
proc = Popen(['ping', ip], stdout=PIPE)
return proc.communicate()[0]
else:
print ("Using Linux / Unix Ping to " + ip)
proc = Popen(['ping', ip, '-c', '4'], stdout=PIPE)
return proc.communicate()[0]
os.system('cls' if os.name=='nt' else 'clear')
print ("Running using threads\n")
start_time = time.time()
pool = Pool(pool_size)
website_names = ["www.google.com","www.facebook.com","www.pinterest.com","www.Microsoft.com"]
result = {}
for website_name in website_names:
result[website_name] = pool.apply_async(do_ping, args=(website_name,))
pool.close()
pool.join()
print ("\n--- Execution took {} seconds ---".format((time.time() - start_time)))
# Now we do the same without threading, just to compare time
print ("\nRunning NOT using threads\n")
start_time = time.time()
for website_name in website_names:
do_ping(website_name)
print ("\n--- Execution took {} seconds ---".format((time.time() - start_time)))
# Here's one way to print the final output from the threads
output = {}
for key, value in result.items():
output[key] = value.get()
print ("\nOutput aggregated in a Dictionary:")
print (output)
print ("\n")
print ("\nPretty printed output:")
for key, value in output.items():
print (key + "\n")
print (value)
Avec les emprunts de this post , nous connaissons les choix entre le multithreading, le multitraitement et leur utilisation asynchrone.
Python3 a une nouvelle bibliothèque intégrée pour la concurrence et le parallélisme: concurrent.futures
Donc, je démontre par une expérience à exécuter quatre tâches (c'est-à-dire .sleep()
méthode) par Threading-Pool
manière:
from concurrent.futures import ThreadPoolExecutor, as_completed
from time import sleep, time
def concurrent(max_worker=1):
futures = []
tick = time()
with ThreadPoolExecutor(max_workers=max_worker) as executor:
futures.append(executor.submit(sleep, 2))
futures.append(executor.submit(sleep, 1))
futures.append(executor.submit(sleep, 7))
futures.append(executor.submit(sleep, 3))
for future in as_completed(futures):
if future.result() is not None:
print(future.result())
print('Total elapsed time by {} workers:'.format(max_worker), time()-tick)
concurrent(5)
concurrent(4)
concurrent(3)
concurrent(2)
concurrent(1)
En dehors:
Total elapsed time by 5 workers: 7.007831811904907
Total elapsed time by 4 workers: 7.007944107055664
Total elapsed time by 3 workers: 7.003149509429932
Total elapsed time by 2 workers: 8.004627466201782
Total elapsed time by 1 workers: 13.013478994369507
[NOTE]:
3
travailleurs quatre que quatre tâches.thread
), vous pouvez modifier le paramètre ThreadPoolExecutor
avec ProcessPoolExecutor
.import threading
myHeavyFctThread = threading.Thread(name='myHeavyFunction', target=myHeavyFunction)
f = threading.Thread(name='foreground', target=foreground)
quand au lieu de myHeavyFunction vous passez le nom de votre fct et quand vous devez activer le fil:
myHeavyFctThread.start()
Je sais que c'est tard, mais je pourrais aider quelqu'un: D