25.1並行性と並列性
-
並行並行性
- スレッド切り替えやタスク切り替えなど、相互の作業切り替え
- マルチスレッド(スレッド切り替え)、コルーチン(タスク切り替え)
-
並列処理
- 同時に、同時に
- マルチプログレス
-
並列または同時?
- 同時実行は通常、I / O操作が頻繁に行われるシナリオで使用されます。たとえば、Webサイトから複数のファイルをダウンロードする場合、I/O操作時間はCPU実行処理時間よりもはるかに長くなる可能性があります。
- 並列処理は、MapReduceでの並列計算など、CPUを多用するシナリオでより多く使用されます。実行速度を高速化するために、通常、複数のマシンと複数のプロセッサーを使用して完了します。
25.2マルチスレッド
Python標準ライブラリは、対応するマルチスレッド/マルチプロセッシングコードを記述するためのスレッドモジュールとマルチプロセッシングモジュールを提供します。マルチスレッドプログラミングは、Python3からconcurrent.futuresモジュールを介してサポートされます。それらの1つはconcurrent.futures.ThreadPoolExecutor()クラスであり、スレッドプールを提供し、マルチスレッドの効率を向上させます。最適なスレッド数を見つけるために、実際のニーズに応じていくつかのテストを実行する必要があります。
コードで学ぶ:
import concurrent.futures # 引入futures模块
import time
import requests
# 定义一个原子任务
def download(url):
resp = requests.get(url, headers={
'User-Agent': "PostmanRuntime/7.24.0"})
print('Download {} from site {}'.format(len(resp.text), url))
return len(resp.text)
# 在多线程中执行原子任务
def download_all(urls):
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor: # 声明一个5个线程的线程池
# worker.map(download, urls) # 不需要download函数的结果时可以这样。
to_do = [] # future列表
results = [] # future的结果列表
for url in urls:
# submit返回创建好的 future 实例,以便之后查询结果使用
future = executor.submit(download, url)
to_do.append(future)
print(to_do)
# as_completed针对给定的 future 迭代器 to_do,返回其完成后的迭代器done_future
for done_future in concurrent.futures.as_completed(to_do):
print(done_future)
# future在done_future里面的顺序,与to_do里面的顺序不一定一致,所以urls与results也不是顺序对应的
results.append(done_future.result()) # result是future执行后的结果或者异常
return results
if __name__ == '__main__':
sites = ['https://movie.douban.com/subject/34805219/',
'https://movie.douban.com/subject/2364086/',
'https://movie.douban.com/subject/33411505',
'https://movie.douban.com/subject/34670959',
'https://movie.douban.com/subject/30403338',
'https://movie.douban.com/subject/30211998',
'https://movie.douban.com/subject/30182726',
'https://movie.douban.com/subject/34670218',
'https://movie.douban.com/subject/26348103',
'https://movie.douban.com/subject/30252495',
'https://movie.douban.com/subject/34805219/',
'https://movie.douban.com/subject/2364086/',
'https://movie.douban.com/subject/33411505',
'https://movie.douban.com/subject/34670959',
'https://movie.douban.com/subject/30403338',
'https://movie.douban.com/subject/30211998',
'https://movie.douban.com/subject/30182726',
'https://movie.douban.com/subject/34670218',
'https://movie.douban.com/subject/26348103',
'https://movie.douban.com/subject/30252495', ]
start_time = time.perf_counter()
res = download_all(sites)
end_time = time.perf_counter()
print("Escape time:", end_time - start_time)
executor.submit(func)を実行すると、内部でfunc()関数の実行が調整され、作成されたfutureインスタンスが返され、後でクエリして呼び出すことができます。
as_completed(fs)、指定された将来のイテレータto_doについて、それが完了した後、完了したイテレータを返します。Futuresには重要な関数result()もあります。これは、完了したイテレーターから対応する結果または例外を取得するために使用されます。
25.3マルチプロセッシング
Python3は、concurrent.futures.ProcessPoolExecutor()プロセスプールクラスを提供します。
マルチプロセスは、並行してプログラム操作の効率を向上させることができます。上記のコードでは、download_all()関数に次の変更を加えるだけです。
with futures.ThreadPoolExecutor(workers) as executor
=>
with futures.ProcessPoolExecutor() as executor:
変更が必要なコードのこの部分では、関数ProcessPoolExecutor()は、プロセスプールを作成し、複数のプロセスを使用してプログラムを並行して実行することを意味します。ただし、システムはCPUの数を、呼び出すことができるプロセスの数として自動的に返すため、通常、ここではパラメーターワーカーを省略します。その他の部分はマルチスレッドと同じです。