web-dev-qa-db-ja.com

Pythonでスレッドを使用する方法

私はPythonでスレッドを理解しようとしています。私はドキュメンテーションと例を見ました、しかし率直に言って、多くの例は過度に洗練されていて、そして私はそれらを理解するのに苦労しています。

どのようにしてタスクがマルチスレッド化のために分割されているのかを明確に示していますか?

1128
albruno

2010年にこの質問が尋ねられて以来、pythonでmapを使用して単純なマルチスレッドを実行する方法が大幅に簡素化されました。およびpool

以下のコードは、間違いなくチェックアウトする必要がある記事/ブログ投稿からのものです(所属なし)-1行の並列性:日々のスレッド化タスクのためのより良いモデル =。以下に要約します-ほんの数行のコードになります:

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

これは、次のマルチスレッドバージョンです。

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

説明

マップはクールな小さな機能であり、Pythonコードに並列処理を簡単に挿入するための鍵です。慣れていない人にとっては、mapはLISPのような関数型言語から解き放たれたものです。これは、シーケンスに別の関数をマッピングする関数です。

Mapはシーケンスの繰り返しを処理し、関数を適用し、最後にすべての結果を便利なリストに保存します。

enter image description here


実装

Map関数の並列バージョンは、2つのライブラリで提供されます:multiprocessingと、あまり知られていないが同様に素晴らしいステップchild:multiprocessing.dummy。

multiprocessing.dummyはマルチプロセッシングモジュールとまったく同じです。 ただし、代わりにスレッドを使用重要な区別 -CPU集中型タスクに複数のプロセスを使用します。 (および中)IO)のスレッド:

multiprocessing.dummyは、マルチプロセッシングのAPIを複製しますが、スレッド化モジュールのラッパーにすぎません。

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

タイミングの結果:

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

複数の引数を渡す(このように動作します Python 3.3以降でのみ ):

複数の配列を渡すには:

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

または定数と配列を渡すには:

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

以前のバージョンのPythonを使用している場合は、 この回避策 を使用して複数の引数を渡すことができます。

(有用なコメントをありがとう ser136036

1312
philshem

これは簡単な例です。あなたはいくつかの代替URLを試して、最初のURLの内容を返す必要があります。

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

これは、スレッド化が単純な最適化として使用される場合です。各サブスレッドは、その内容をキューに入れるために、URLの解決と応答を待機しています。各スレッドはデーモンです(メインスレッドが終了してもプロセスを維持できません - これは一般的ではないより一般的です)。メインスレッドはすべてのサブスレッドを開始し、キューのgetを実行していずれかのサブスレッドがputを実行するまで待機してから結果を出力して終了します(デーモンスレッドのため、実行中のサブスレッドはすべて停止します)。

Pythonでスレッドを適切に使用することは常にI/O操作に関係しています(CPythonはCPUコアのタスクを実行するために複数のコアを使用しないため、スレッド化の唯一の理由はI/Oを待つ間プロセスをブロックしないことです) )ところで、キューはほとんど常にスレッドへの作業の集約や作業の結果の収集のための最善の方法であり、本質的にスレッドセーフであるため、ロック、条件、イベント、セマフォなどの心配をする必要はありません。スレッド調整/通信の概念.

698
Alex Martelli

注意:実際のPythonの並列化のためには、 multiprocessing モジュールを使って並列に実行する複数のプロセスをforkするべきです(グローバルインタプリタロックのため、Pythonスレッドはインターリーブを提供しますが実際は並列ではなく直列に実行されます入出力操作をインターリーブする場合にのみ有用です。

しかし、単にインターリーブを探している(またはグローバルインタプリタロックにもかかわらず並列化できるI/O操作を行っている)場合は、 threading モジュールが開始する場所です。非常に単純な例として、サブレンジを並列に合計することによって広い範囲を合計する問題を考えてみましょう。

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

グローバルインタープリタロックのためにCPythonではインターリーブされていますが(コンテキスト切り替えのオーバーヘッドが追加されますが)、上記は非常に愚かな例です。I/ Oは絶対に行われず、シリアルに実行されます。

244

他の人が言ったように、CPythonはGILのためにI\O待機のためだけにスレッドを使うことができます。 CPUに束縛されたタスクに対して複数のコアから利益を得たい場合は、 multiprocessing を使用してください。

from multiprocessing import Process

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

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

ちなみに、Queueはスレッド化には必要ありません。

これは私が想像できる最も簡単な例で、10個のプロセスが同時に実行されていることを示しています。

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

Alex Martelliからの回答は私を助けてくれました、しかしここに私がもっと役に立つと思った修正版があります(少なくとも私には)。

更新: python2と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()
44
JimJty

私はこれが非常に便利だと思いました:コアと同数のスレッドを作成し、それらに(この場合はシェルプログラムを呼び出す)たくさんのタスクを実行させます:

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

関数fが与えられると、それを次のようにスレッド化します。

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

fに引数を渡すには

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

Python 3は 並列タスクの起動 の機能を持っています。これにより作業が容易になります。

スレッドプーリング および プロセスプーリング があります。

以下は洞察を与えます:

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

私にとって、スレッド化の完璧な例は非同期イベントの監視です。このコードを見てください。

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

あなたはIPythonセッションを開いて以下のようなことをすることによってこのコードで遊ぶことができます:

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

数分待つ

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

燃えるような新しい 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())

エグゼキュータによるアプローチは、以前にJavaを使ったことがある人にはおなじみのものかもしれません。

念のために言っておきましょう。withコンテキストを使用しない場合は、ユニバースを安全に保つために、プール/エグゼキュータを閉じることを忘れないでください(これはあなたにとってそれをするのに素晴らしいことです)。

14

ほとんどのドキュメントとチュートリアルはPythonのThreadingQueueモジュールを使っています。

おそらくpython 3のconcurrent.futures.ThreadPoolExecutorモジュールを考えてみてください。with句とリスト内包表記を組み合わせることは、本当に魅力的なことです。

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

これはスレッドを使ったCSVインポートの非常に簡単な例です。 [図書館に含まれるものは目的によって異なる場合があります]

ヘルパー関数

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

ドライバー機能:

import_handler(csv_file_name) 
11
Chirag Vora

ここでは実際の作業は行われていないという例がたくさん見られました。それらは主にCPUの制約を受けていました。これは、1000万から10000万の間のすべての素数を計算するCPUバウンドタスクの例です。ここでは4つの方法すべてを使用しました

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

これが私の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
8
PirateApp

簡単な例でのマルチスレッドが役に立つでしょう。これを実行して、pythonでマルチスレッドがどのように機能するのかを簡単に理解することができます。以前のスレッドが作業を終了するまで他のスレッドにアクセスしないようにするためにlockを使用しました。の使用によって

tLock = threading.BoundedSemaphore(値= 4)

このコード行を使用すると、一度に多数のプロセスを許可して、後で実行されるスレッドや前のプロセスが終了した後に実行されるスレッドの残りの部分を保持できます。

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

上記の解決法のどれも実際に私のGNU/Linuxサーバ(私は管理者権限を持っていないところ)で複数のコアを使っていませんでした。彼らはただシングルコアで走りました。私はより低いレベルのos.forkインターフェースを使用して複数のプロセスを生成しました。これは私のために働いたコードです:

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

簡単な例と、この問題に自分で取り組む必要があるときに見つけた説明で貢献したいと思います。

ここでは、GILに関する便利な情報と、簡単な日々の例(multiprocessing.dummyを使用)およびマルチスレッドを使用した場合と使用しない場合のベンチマークを貼り付けます。

グローバルインタープリターロック(GIL)

Pythonは、Wordの真の意味でのマルチスレッドを許可していません。マルチスレッドパッケージがありますが、コードを高速化するためにマルチスレッドを使用する場合は、通常、使用することはお勧めできません。 Pythonには、Global Interpreter Lock(GIL)と呼ばれる構造があります。 GILは、一度に1つのスレッドのみが実行できるようにします。スレッドはGILを取得し、少し作業を行ってから、GILを次のスレッドに渡します。これは非常に迅速に行われるため、人間の目にはスレッドが並列に実行されているように見えるかもしれませんが、実際には同じCPUコアを使用して交互に実行しています。このすべてのGILの受け渡しは、実行にオーバーヘッドを追加します。これは、コードをより速く実行したい場合、スレッドパッケージを使用することはよくないことを意味します。

Pythonのスレッドパッケージを使用する理由があります。いくつかの処理を同時に実行したい場合で、効率が問題にならない場合は、まったく問題なく便利です。または、何か(IOなど)を待つ必要があるコードを実行している場合、それは非常に理にかなっています。ただし、スレッドライブラリでは、追加のCPUコアを使用できません。

マルチスレッド化は、(マルチプロセッシングを行うことにより)オペレーティングシステム、Pythonコード(たとえば、SparkまたはHadoop)を呼び出す外部アプリケーション、またはPythonコードの呼び出し(例:Pythonコードに、高価なマルチスレッド処理を行うC関数を呼び出すこともできます)。

なぜこれが重要なのか

多くの人が、GILが何であるかを学ぶ前に、空想的なPythonマルチスレッドコードのボトルネックを見つけるために多くの時間を費やしているからです。

この情報が明確になったら、私のコードを次に示します。

#!/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

この記事から を借用して/私たちはマルチスレッド、マルチプロセッシング、そしてそれらの使用法の非同期の間の選択を知っています。

Python3は並行性と並列性のために新しい組み込みライブラリを持っています: concurrent.futures

だから私はThreading-Poolの方法で4つのタスク(すなわち.sleep()メソッド)を実行する実験で実証します。

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)

でる:

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の4人から4人の作業でした。
  • I/Oバウンド(threadを使用)の代わりにプロセスタスクがある場合は、ThreadPoolExecutorProcessPoolExecutorで変更できます。
0
Benyamin Jafari
import threading   
myHeavyFctThread = threading.Thread(name='myHeavyFunction', target=myHeavyFunction)
f = threading.Thread(name='foreground', target=foreground)

myHeavyFunctionの代わりに、fctの名前を渡し、スレッドをアクティブにする必要がある場合:

myHeavyFctThread.start()

私はその遅れを知っているが、誰かを助けるかもしれない:D

0
TheCondorIV