it-swarm.com.de

Wie verwende ich Threading in Python?

Ich versuche, Threading in Python zu verstehen. Ich habe mir die Dokumentation und die Beispiele angesehen, aber ehrlich gesagt sind viele Beispiele zu hoch entwickelt und ich habe Probleme, sie zu verstehen.

Wie lassen sich Aufgaben für Multithreading klar aufteilen?

1177
albruno

Seitdem diese Frage im Jahr 2010 gestellt wurde, wurde das einfache Multithreading mit python mit map und - wirklich vereinfacht. Pool.

Der folgende Code stammt aus einem Artikel/Blog-Beitrag, den Sie unbedingt lesen sollten (keine Zugehörigkeit) - Parallelität in einer Zeile: Ein besseres Modell für tägliche Threading-Aufgaben. Ich fasse es unten zusammen - am Ende sind es nur ein paar Zeilen Code:

from multiprocessing.dummy import Pool as ThreadPool 
pool = ThreadPool(4) 
results = pool.map(my_function, my_array)

Welches ist die Multithread-Version von:

results = []
for item in my_array:
    results.append(my_function(item))

Beschreibung

Map ist eine coole kleine Funktion und der Schlüssel zum einfachen Einfügen von Parallelität in Ihren Python Code. Für Unbekannte ist map etwas, das aus funktionalen Sprachen wie LISP herausgenommen wurde. Es ist eine Funktion, die eine andere Funktion über eine Sequenz abbildet.

Map wendet die Iteration über die Sequenz für uns an, wendet die Funktion an und speichert alle Ergebnisse am Ende in einer praktischen Liste.

enter image description here


Implementierung

Parallele Versionen der Kartenfunktion werden von zwei Bibliotheken bereitgestellt: Multiprocessing und auch das wenig bekannte, aber ebenso fantastische Stiefkind: multiprocessing.dummy.

multiprocessing.dummy ist genau das gleiche wie das Multiprocessing-Modul verwendet jedoch stattdessen Threads (ein wichtiger Unterschied - verwendet mehrere Prozesse für CPU-intensive Aufgaben; Threads für (und während) IO ):

multiprocessing.dummy repliziert die API von multiprocessing, ist jedoch nur ein Wrapper um das Threading-Modul.

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() 

Und die Timing-Ergebnisse:

Single thread:   14.4 seconds
       4 Pool:   3.1 seconds
       8 Pool:   1.4 seconds
      13 Pool:   1.3 seconds

Mehrere Argumente übergeben (funktioniert wie folgt nur in Python 3.3 und höher ):

So übergeben Sie mehrere Arrays:

results = pool.starmap(function, Zip(list_a, list_b))

oder um eine Konstante und ein Array zu übergeben:

results = pool.starmap(function, Zip(itertools.repeat(constant), list_a))

Wenn Sie eine frühere Version von Python verwenden, können Sie mehrere Argumente über diese Problemumgehung übergeben.

(Danke an ser136036 für den hilfreichen Kommentar)

1312
philshem

Hier ist ein einfaches Beispiel: Sie müssen ein paar alternative URLs ausprobieren und den Inhalt der ersten URL zurückgeben, die antwortet.

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

Dies ist ein Fall, in dem Threading als einfache Optimierung verwendet wird: Jeder Subthread wartet darauf, dass eine URL aufgelöst wird und antwortet, um seinen Inhalt in die Warteschlange zu stellen. Jeder Thread ist ein Daemon (hält den Prozess nicht aufrecht, wenn der Haupt-Thread endet - das ist häufiger als nicht). Der Hauptthread startet alle Unterthreads, wartet in der Warteschlange mit einem get, bis einer von ihnen ein put ausgeführt hat, gibt dann die Ergebnisse aus und bricht ab (wodurch alle möglicherweise noch ausgeführten Unterthreads beendet werden). da sie Daemon-Threads sind).

Die ordnungsgemäße Verwendung von Threads in Python ist ausnahmslos mit E/A-Vorgängen verbunden (da CPython ohnehin nicht mehrere Kerne zum Ausführen von CPU-gebundenen Aufgaben verwendet, ist der einzige Grund für das Threading, den Prozess nicht zu blockieren, solange ein vorhanden ist warte auf ein I/O). Warteschlangen sind übrigens fast immer die beste Methode, um Arbeit an Threads auszulagern und/oder die Ergebnisse der Arbeit zu sammeln, und sie sind von sich aus threadsicher, sodass Sie sich keine Gedanken über Sperren, Bedingungen, Ereignisse, Semaphoren und andere Zwischenfälle machen müssen. Thread-Koordination/Kommunikationskonzepte.

703
Alex Martelli

HINWEIS: Für die eigentliche Parallelisierung in Python sollten Sie das Modul Multiprocessing verwenden, um mehrere Prozesse abzweigen, die parallel ausgeführt werden (aufgrund der globalen Interpretersperre bieten Python Threads Interleaving, sind aber tatsächlich seriell ausgeführt, nicht parallel und nur beim Verschachteln von E/A-Operationen nützlich).

Wenn Sie jedoch nur nach Interleaving suchen (oder E/A-Operationen ausführen, die trotz der globalen Interpretersperre parallelisiert werden können), ist das Modul Threading der Ausgangspunkt. Als ein wirklich einfaches Beispiel betrachten wir das Problem des Summierens eines großen Bereichs durch paralleles Summieren von Teilbereichen:

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

Beachten Sie, dass das oben genannte Beispiel sehr dumm ist, da es absolut keine E/A-Vorgänge ausführt und seriell ausgeführt wird, obwohl es aufgrund der globalen Interpretersperre in CPython verschachtelt ist (mit dem zusätzlichen Overhead der Kontextumschaltung).

250

Wie bereits erwähnt, kann CPython Threads nur für E/A-Wartezeiten aufgrund von GIL verwenden. Wenn Sie für CPU-gebundene Aufgaben von mehreren Kernen profitieren möchten, verwenden Sie Multiprocessing :

from multiprocessing import Process

def f(name):
    print 'hello', name

if __== '__main__':
    p = Process(target=f, args=('bob',))
    p.start()
    p.join()
98
Kai

Nur eine Anmerkung, Queue wird zum Threading nicht benötigt.

Dies ist das einfachste Beispiel, das ich mir vorstellen kann und das zeigt, dass 10 Prozesse gleichzeitig ausgeführt werden.

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"
90
Douglas Adams

Die Antwort von Alex Martelli hat mir geholfen, aber hier ist eine modifizierte Version, die ich für nützlicher hielt (zumindest für mich).

pdated: funktioniert sowohl in Python2 als auch in 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()
47
JimJty

Ich fand das sehr nützlich: Erstelle so viele Threads wie Kerne und lasse sie eine (große) Anzahl von Tasks ausführen (in diesem Fall ein Shell-Programm aufrufen):

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
23
dolphin

Fädle eine gegebene Funktion, f, so ein:

import threading
threading.Thread(target=f).start()

Argumente an f übergeben

threading.Thread(target=f, args=(a,b,c)).start()
22
starfry

Python 3 bietet die Möglichkeit, parallele Tasks starten . Das erleichtert uns die Arbeit.

Es hat für Thread-Pooling und Prozess-Pooling .

Folgendes gibt einen Einblick:

ThreadPoolExecutor Beispiel

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()
20
Jeril

Für mich ist das perfekte Beispiel für Threading die Überwachung von asynchronen Ereignissen. Schau dir diesen Code an.

# 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;

Sie können mit diesem Code spielen, indem Sie eine IPython-Sitzung öffnen und Folgendes ausführen:

>>>from thread_test import Monitor
>>>a = [0]
>>>mon = Monitor(a)
>>>mon.start()
>>>a[0] = 2
Mon = 2
>>>a[0] = 2
Mon = 2

Warte ein paar Minuten

>>>a[0] = 2
Mon = 2
18
dvreed77

Verwenden Sie das brandneue concurrent.futures Modul

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())

Der Executor-Ansatz scheint all jenen vertraut zu sein, die sich zuvor mit Java die Hände schmutzig gemacht haben.

Ebenfalls eine Randnotiz: Um das Universum gesund zu halten, vergessen Sie nicht, Ihre Pools/Executoren zu schließen, wenn Sie den with -Kontext nicht verwenden (was so fantastisch ist, dass es das für Sie tut).

17

Die meisten Dokumentationen und Tutorials verwenden Pythons Threading und Queue Modul, die für Anfänger überwältigend erscheinen könnten.

Betrachten Sie vielleicht das concurrent.futures.ThreadPoolExecutor -Modul von python 3. In Kombination mit der with -Klausel und dem Listenverständnis könnte dies ein echter Reiz sein.

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()
15
Yibo

Ich habe hier viele Beispiele gesehen, bei denen keine wirkliche Arbeit geleistet wurde und die größtenteils CPU-gebunden waren. Hier ist ein Beispiel für eine CPU-gebundene Task, die alle Primzahlen zwischen 10 Millionen und 10,05 Millionen berechnet. Ich habe alle 4 Methoden hier verwendet

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()

Hier sind die Ergebnisse auf meinem Mac OSX 4-Kerncomputer

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
12
PirateApp

Hier ist das sehr einfache Beispiel eines CSV-Imports mit Threading. [Der Einschluss der Bibliothek kann für verschiedene Zwecke unterschiedlich sein.]

Hilfsfunktionen:

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

Treiberfunktion:

import_handler(csv_file_name) 
11
Chirag Vora

Multi-Threading mit einfachem Beispiel, das hilfreich sein wird. Sie können es ausführen und leicht verstehen, wie Multi-Thread in Python funktioniert. Ich habe lock verwendet, um zu verhindern, dass auf andere Threads zugegriffen wird, bis frühere Threads ihre Arbeit beendet haben. Durch die Verwendung von

tLock = threading.BoundedSemaphore (Wert = 4)

mit dieser Codezeile können Sie eine bestimmte Anzahl von Prozessen gleichzeitig zulassen und den Rest des Threads beibehalten, der später oder nach Abschluss der vorherigen Prozesse ausgeführt wird.

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()
7
cSharma

Keine der oben genannten Lösungen verwendete tatsächlich mehrere Kerne auf meinem GNU/Linux-Server (wo ich keine Administratorrechte habe). Sie liefen nur auf einem einzigen Kern. Ich habe die os.fork -Schnittstelle der unteren Ebene verwendet, um mehrere Prozesse zu erzeugen. Dies ist der Code, der für mich funktioniert hat:

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
3
David Nathan
import threading
import requests

def send():

  r = requests.get('https://www.stackoverlow.com')

thread = []
t = threading.Thread(target=send())
thread.append(t)
t.start()
2
Skiller Dz

Ich möchte mit einem einfachen Beispiel und den Erklärungen dazu beitragen, dass ich dieses Problem selbst angehen musste.

Hier füge ich einige nützliche Informationen zu GIL und ein einfaches tägliches Beispiel (unter Verwendung von multiprocessing.dummy) und dessen Benchmarks mit und ohne Multithreading ein.

Global Interpreter Lock (GIL)

Python erlaubt kein Multithreading im wahrsten Sinne des Wortes. Es hat ein Multithreading-Paket, aber wenn Sie den Code mit mehreren Threads beschleunigen möchten, ist es normalerweise keine gute Idee, es zu verwenden. Python hat ein Konstrukt namens Global Interpreter Lock (GIL). Die GIL stellt sicher, dass immer nur einer Ihrer Threads ausgeführt werden kann. Ein Thread erwirbt die GIL, erledigt ein wenig Arbeit und leitet sie dann an den nächsten Thread weiter. Dies geschieht sehr schnell, so dass es für das menschliche Auge so aussieht, als würden Ihre Threads parallel ausgeführt, aber sie wechseln sich wirklich nur mit demselben CPU-Kern ab. All diese GIL-Übergabe erhöht den Aufwand für die Ausführung. Dies bedeutet, dass die Verwendung des Threading-Pakets oft keine gute Idee ist, wenn Sie den Code schneller ausführen möchten.

Es gibt Gründe, das Threading-Paket von Python zu verwenden. Wenn Sie einige Dinge gleichzeitig ausführen möchten und die Effizienz keine Rolle spielt, ist dies in Ordnung und praktisch. Oder wenn Sie Code ausführen, der auf etwas warten muss (z. B. auf E/A), kann dies sehr sinnvoll sein. In der Threading-Bibliothek können Sie jedoch keine zusätzlichen CPU-Kerne verwenden.

Multi-Threading kann an das Betriebssystem ausgelagert werden (durch Multi-Processing), durch eine externe Anwendung, die Ihren Python Code aufruft (z. B. Spark oder Hadoop), oder durch einen Code, der diesen aufruft Ihre Python Code-Aufrufe (zB: Sie könnten Ihren Python Code eine C-Funktion aufrufen lassen, die die teuren Multithread-Aufgaben erledigt).

Warum das wichtig ist

Weil viele Leute viel Zeit damit verbringen, Engpässe in ihrem ausgefallenen Python Multithread-Code zu finden, bevor sie erfahren, was die GIL ist.

Sobald diese Informationen klar sind, ist hier mein 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)
0
Pitto

Mit Ausleihen von diesem Beitrag kennen wir die Wahl zwischen Multithreading, Multiprocessing und asynchroner Verwendung.

Python3 verfügt über eine neue integrierte Bibliothek, um Parallelität und Parallelität zu gewährleisten: concurrent.futures

Also demonstriere ich durch ein Experiment, wie man vier Tasks (d. H. Die .sleep() -Methode) auf Threading-Pool Weise ausführt:

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)

Aus:

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]:

  • Wie Sie in den obigen Ergebnissen sehen können, waren 3 Arbeiter vier vor vier Aufgaben der beste Fall.
  • Wenn Sie eine Prozessaufgabe anstelle einer E/A-Bindung haben (mit thread), können Sie die ThreadPoolExecutor mit ProcessPoolExecutor ändern.
0
Benyamin Jafari
import threading   
myHeavyFctThread = threading.Thread(name='myHeavyFunction', target=myHeavyFunction)
f = threading.Thread(name='foreground', target=foreground)

wenn du anstelle von myHeavyFunction den Namen deines FCTs übergibst und wenn du den Thread aktivieren musst:

myHeavyFctThread.start()

Ich weiß, dass es spät ist, könnte aber jemandem helfen: D

0
TheCondorIV