Pythonスレッドには典型的な問題であるGIL(グローバルコントロールロック、つまり、Pythonが特定の時間に実行できるスレッドは1つだけです)があるので、マルチスレッド化はどのように行われますか?実装?
回答:I / O集中型のタスクの処理では、リクエストを待機すると、PythonのI / O関数が自動的にGILを解放してスレッドを実行するため、I / O時間が短縮されます。これは、並行処理です。実装メソッドには、concurrent.futureモジュール(futures.ThreadPoolExecutorクラス)とスレッドモジュールが含まれます。
Pythonは真の並列処理を実現できますか?マルチプロセスとは一体何ですか?複数のプロセスはより速くなりますか?
回答:これで結構です並列タスクを実行するCPUの数を選択できるので、マルチプロセスタスクを実行できます。マルチプロセスの並列処理は、マルチスレッドよりも高速である必要はありません。2つのアプリケーションフィールドは異なります。マルチプロセスは、CPU集中型(多数の数値計算、すべて実行中のメモリ内)操作に適しており、マルチスレッドはI / O集中型(およびディスクにはインタラクティブな動作)があります。実装メソッドには、スレッド化モジュール、mutiprocessingモジュール、futures.ProcessPoolExecutorクラスが含まれます。
最初にマルチスレッディングを実装しましょう、それはより簡単に思えます。
In [65]: import requests
In [66]: import tqdm
In [67]: import os
In [68]: import time
In [69]: import sys
In [70]: POP_CC= ('CC,IN,US,ID,BP').split()
In [71]: BASE_URL = 'http://flupy.org/data/flags'
In [72]: DEST_DIR = 'downloads/'
In [73]: def save_flag(img,filename):
...: path = os.path.join(DEST_DIR,filename)
...: with open(path,'wb') as fp:
...: fp.write(img)
...:
In [74]: def get_flag(cc):
...: url = '{}/{cc}/{cc}.gif'.format(BASE_URL,cc=cc.lower())
...: resp = requests.get(url)
...: return resp.content
...:
In [75]: def show(text):
...: print(text,end='')
...: sys.stdout.flush()
...:
In [76]: def download_one(cc): # 技巧,所有基操都放在一个里
...: image = get_flag(cc)
...: show(cc)
...: save_flag(image,cc.lower()+'.gif')
...: return cc
...:
In [77]: MAX_WORKERS = 20 # 20个线程
In [78]: def download_many(cc_list):
...: workers = min(MAX_WORKERS,len(cc_list)) # 任务少的话开多没用
...: with futures.ThreadPoolExecutor(workers) as executor:
...: res = executor.map(download_one,tqdm.tqdm(sorted(cc_list))) # 其实经历了future实例的过程,可以细究,不过单纯实现不需要知道,tqdm显示进度条
...: return len(list(res))
...:
In [79]: def main(download_many):
...: t0 = time.time()
...: count = download_many(POP_CC)
...: elapsed = time.time()-t0
...: msg = '\n{} flags downloaded in {:.2f}s'
...: print(msg.format(count,elapsed))
...:
In [80]: if __name__ == 'main':
...: main(download_many)