Python学習【365日チャレンジ!】229日目のマスターU(@Udemy11)です。
Google翻訳の使い勝手が向上してから、他の翻訳ツールを使ってはいなかったのですが、iOS14の純正翻訳アプリとGoogle翻訳などと使い勝手を比較している記事があったので、ちらっとのぞいてみました。
いったいAppleは何をしているのか?というくらい、純正アプリのできの悪さにも驚きですが、Google翻訳よりも精度の高い【DeepL】という翻訳サイトを知って衝撃を受けています。
アプリではなくてWeb翻訳なのですが、Google翻訳よりも日本語っぽい翻訳をしてくれるので、Pythonのドキュメンテーションや英語のニュース記事などを読むのが楽になります。
iPhoneのホーム画面に登録して使えるので、ぜひ使ってみてください。
ホーム画面への登録方法はこちらの記事が参考になります。
それでは、今日もPython学習をはじめましょう。
昨日の復習
昨日は、他のマシンで走るプロセスをネットワーク越しに共有する方法について学習しました。
サーバーとクライアントのファイルを作成して、データのやり取りをしましたが、2つのクライアントのうち、データを受け取るほうが入力を待っている状態になっていたり、その状態でデータが入力されたらすぐにデータを受け取って出力されたりするコードを書いてみました。
ネットワークでのデータやり取りは、プログラムの醍醐味ともいえるので、いろいろとコードを変更しながら試してみました。
詳細については、昨日の記事をごらんください。
今日は、スレッドでの並列処理を簡単にできるThreadPoolExecutor
を学習します。
concurrent.futures
threading
やmultiprocessing
を使って、スレッドやプロセスの並列処理ができましたが、concurrent.futures
を使えば、より簡単にスレッドやプロセスの並列処理を扱うことができます。
まずは、Thread
について、concurrent.futures
を使った並列処理のコードを書いてみたいと思います。
import concurrent.futures
import logging
logging.basicConfig(
level=logging.DEBUG, format='%(threadName)s: %(message)s'
)
def worker(x, y):
logging.debug('start')
r = x * y
logging.debug(r)
logging.debug('end')
return r
if __name__ == '__main__':
with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor:
f1 = executor.submit(worker, 2, 5)
f2 = executor.submit(worker, 2, 5)
logging.debug(f1.result())
logging.debug(f2.result())
最初にconcurrent.futures
をインポートして、ロギングについてのコードは、これまで同様に、デバッグでスレッド名とメッセージが出力されるようなコードにしています。
if
以下の実行コードには、ThreadPoolExecutor
を使って、引数のmax_workers
に2
を指定して、います。
17行目、18行目で上記の関数worker
をターゲットにして、2
と5
を引数に入れたオブジェクトf1
、f2
を作成して、19行目と20行目でworker
から返ってくる値を出力しています。
実行結果
ThreadPoolExecutor-0_0: start
ThreadPoolExecutor-0_0: 10
ThreadPoolExecutor-0_0: end
MainThread: 10
ThreadPoolExecutor-0_0: start
ThreadPoolExecutor-0_0: 10
ThreadPoolExecutor-0_0: end
MainThread: 10
スレッド名がThreadPoolExecutor
になって、start
、10
、end
が出力されたあと、MainThread
で返り値の10
が出力されています。
同じ出力をもう一回繰り返してプログラムが終了しています。
16行目のmax_worker
は、並列処理ができるスレッドの数なので、この値を1
にすると並列処理をせずに、一つ一つスレッドを処理していきます。
map
次は、ThreadPoolExecutor
で、並列処理が終了してから次のコードの処理をするmap
を使ってみましょう。
if __name__ == '__main__':
with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor:
args = [[2, 2], [5, 5]]
r = executor.map(worker, *args)
logging.debug(r)
logging.debug([i for i in r])
15行目からを変更します。
15行目のexecutor
は同じで、16行目のリストargs
引数を2つづつに入れています。
17行目でmap
でターゲットをworker
と引数に*args
を指定して、r
を出力、20行目でリスト内包表記で返り値をリストで返しています。
実行結果
ThreadPoolExecutor-0_0: start
ThreadPoolExecutor-0_0: 10
ThreadPoolExecutor-0_0: end
ThreadPoolExecutor-0_0: start
ThreadPoolExecutor-0_0: 10
ThreadPoolExecutor-0_0: end
MainThread: .result_iterator at 0x7fc14287abd0>
MainThread: [10, 10]
出力の7行目は、r
を出力していますが、ジェネレーターオブジェクトで、イテレーターであることがわかります。
最終行で返り値がリストで出力されています。
色々試す
これまでのエントリーでもそうですが、サンプルコードを紹介していますが、関数の処理の間にtime.sleep
を入れてみるとか、プリント出力してみるなど、ちょっとコードを変えて実行してみると、エラーが起こったり、出力が変わったりするので、色々と試してみてください。
ほんと、トライ&エラーは大切ですよ。
それでは、明日もGood Python!