7.1非同期ノウハウ
1.同期
我々は2つのクライアント要求をシミュレートし、プロセスを実行するために2つの関数を使用します。
#!は/ usr / binに/ ENVのpython3 #- * -コーディング:UTF-8 - * - # @time:2020年3月9日午前11時15分 # @author:zhangmingda # @file:asynchronization.py # @Software:PyCharm # 説明:非同期の作品を理解 DEF REQ_Aを(): '' ' シミュレーション要求A ' '' 印刷(' リクエストAの処理開始' ) を印刷(' 完全な処理要求A ' ) DEF REQ_Bを(): '' ' シミュレーション要求A 「」「 印刷(」リクエストBの処理を開始します") 印刷(' 完全な処理要求B ' ) DEF メイン(): "" " アナログ竜巻フレーム、2つの要求を処理する" "" REQ_A() REQ_B() IF __name__ == " __main__ " : main()の
結果:
D:\ Python3_study \ tornado1 \スクリプト \ python.exeのD:/Python3_study/tornado1/asynchronization.pyは、
要求Aの処理開始
の完全な処理要求Aの
リクエストBの処理を開始する
処理要求Bを完成さ
同期が常に同一工程で行われる工程、により順次ステップを実行し、ステップは次のステップを実行しません。
あなたが要求REQ_A、どのようにその実行を処理している間(例えばIOなど)時間のかかるタスクを実行する必要がある場合は、それについて考えてみようか?
インポート時間 DEF REQ_A(): '' ' シミュレーション要求A ' '' 印刷(' リクエストAの処理を開始' ) long_io() 印刷(' 完全な処理要求A ' ) DEF REQ_B(): '' ' シミュレーション要求A ' ' 「 プリント(」リクエストBの処理を開始「) 印刷(」完全な処理要求B ' ) DEF )(主: 『』 『アナログ竜巻フレームを、2つの要求を処理します』 『』 REQ_A() REQ_B() DEF long_io(): ''」IOアナログ時間のかかる操作を'' ' 印刷(' IO操作を開始" ) time.sleepを( 5。 ) 印刷(" 完全なIO操作" ) 復帰 " IO ComPlateを!! " IF __name__ == " __main__ " : main()の
実装プロセス:
D:\ Python3_study \ tornado1 \スクリプト \ python.exe D:/Python3_study/tornado1/asynchronization.pyは
Aが要求処理を開始する
動作IO開始
完了IO動作
Aの処理完了要求が
要求Bが処理を開始する
処理要求Bを完了するを
上記のテストでは、我々はREQ_A未処理の完成REQ_B法的強制力という、ライブブロックのコードを実行するために時間のかかる操作を参照してください。
どのように我々は時間のかかる操作のブロッキングコードの実行を解決しますか?
2.非同期
人々が終了したときに時間のかかるプロセスのために、私たちは(例えばその別のスレッドとして)実行するために他の誰かにそれを与える、と私たちはダウンに対処していき、時間のかかる操作をして、結果は私たちに戻り、これは我々が非同期呼んでいます。
私たちは、非同期スレッドを実装するためのメカニズムを理解するために使いやすいです。
2.1書き込みコールバックの原則
# coding:utf-8
import time
import thread
def long_io(callback): """将耗时的操作交给另一线程来处理""" def fun(cb): # 回调函数作为参数 """耗时操作""" print "开始执行IO操作" time.sleep(5) print "完成IO操作,并执行回调函数" cb("io result") # 执行回调函数 thread.start_new_thread(fun, (callback,)) # 开启线程执行耗时操作 def on_finish(ret): """回调函数""" print "开始执行回调函数on_finish" print "ret: %s" % ret print "完成执行回调函数on_finish" def req_a(): print "开始处理请求req_a" long_io(on_finish) print "离开处理请求req_a" def req_b(): print "开始处理请求req_b" time.sleep(2) # 添加此句来突出显示程序执行的过程 print "完成处理请求req_b" def main(): req_a() req_b() while 1: # 添加此句防止程序退出,保证线程可以执行完 pass if __name__ == '__main__': main()
実装プロセス:
开始处理请求req_a
离开处理请求req_a
开始处理请求req_b
开始执行IO操作
完成处理请求req_b
完成IO操作,并执行回调函数
开始执行回调函数on_finish
ret: io result
完成执行回调函数on_finish
複数の非同期プログラムステップの存在によって特徴付けられる、同じプロセスに属している、すなわち符号が異なるペースで同時に行ってもよいです。
2.2コルーチンを書くの原則
コールバック関数の非同期を使用してプログラムを書くときに、本ロジック(処理要求A)に属している必要が2つのコードが実行されると機能に分割さが大きく変化する同期プログラムが書き込まれ、on_finish REQ_A。同期プログラム我々は、非同期プログラムを書くために文言同期コードを使用することができますので、ビジネスロジックを理解しやすいですか?
キーワードの役割をもたらすリコール?
初期リリース
# coding:utf-8
import time
import thread
gen = None # 全局生成器,供long_io使用 def long_io(): def fun(): print "开始执行IO操作" global gen time.sleep(5) try: print "完成IO操作,并send结果唤醒挂起程序继续执行" gen.send("io result") # 使用send返回结果并唤醒程序继续执行 except StopIteration: # 捕获生成器完成迭代,防止程序退出 pass thread.start_new_thread(fun, ()) def req_a(): print "开始处理请求req_a" ret = yield long_io() print "ret: %s" % ret print "完成处理请求req_a" def req_b(): print "开始处理请求req_b" time.sleep(2) print "完成处理请求req_b" def main(): global gen gen = req_a() gen.next() # 开启生成器req_a的执行 req_b() while 1: pass if __name__ == '__main__': main()
実装プロセス:
开始处理请求req_a
开始处理请求req_b
开始执行IO操作
完成处理请求req_b
完成IO操作,并send结果唤醒挂起程序继续执行
ret: io result
完成处理请求req_a
アップグレード版
我々は、ウェイREQ_Aに書き込まれた同期コードと非常によく似ているが、上記バージョンで書くが、主コールそれは単に通常の関数とみなすことができないREQ_Aが、必要に発電機として扱われます。
今、私たちは、書き込みREQ_Aがメイン同期コードに似ていますので、変更しようとしようとしています。
# coding:utf-8
import time
import thread
gen = None # 全局生成器,供long_io使用 def gen_coroutine(f): def wrapper(*args, **kwargs): global gen gen = f() gen.next() return wrapper def long_io(): def fun(): print "开始执行IO操作" global gen time.sleep(5) try: print "完成IO操作,并send结果唤醒挂起程序继续执行" gen.send("io result") # 使用send返回结果并唤醒程序继续执行 except StopIteration: # 捕获生成器完成迭代,防止程序退出 pass thread.start_new_thread(fun, ()) @gen_coroutine def req_a(): print "开始处理请求req_a" ret = yield long_io() print "ret: %s" % ret print "完成处理请求req_a" def req_b(): print "开始处理请求req_b" time.sleep(2) print "完成处理请求req_b" def main(): req_a() req_b() while 1: pass if __name__ == '__main__': main()
実装プロセス:
开始处理请求req_a
开始处理请求req_b
开始执行IO操作
完成处理请求req_b
完成IO操作,并send结果唤醒挂起程序继续执行
ret: io result
完成处理请求req_a
最終版
ただ、完成版の使用にlong_io世代のためのグローバル変数があるので、まだ理想的ではありません。私たちは今、再びグローバル変数GENの排除をプログラムを書き換えます。
# coding:utf-8
import time
import thread
def gen_coroutine(f): def wrapper(*args, **kwargs): gen_f = f() # gen_f为生成器req_a r = gen_f.next() # r为生成器long_io def fun(g): ret = g.next() # 执行生成器long_io try: gen_f.send(ret) # 将结果返回给req_a并使其继续执行 except StopIteration: pass thread.start_new_thread(fun, (r,)) return wrapper def long_io(): print "开始执行IO操作" time.sleep(5) print "完成IO操作,yield回操作结果" yield "io result" @gen_coroutine def req_a(): print "开始处理请求req_a" ret = yield long_io() print "ret: %s" % ret print "完成处理请求req_a" def req_b(): print "开始处理请求req_b" time.sleep(2) print "完成处理请求req_b" def main(): req_a() req_b() while 1: pass if __name__ == '__main__': main()
実装プロセス:
开始处理请求req_a
开始处理请求req_b
开始执行IO操作
完成处理请求req_b
完成IO操作,yield回操作结果
ret: io result
完成处理请求req_a
最終版は、最も単純な非同期プログラミングモデルトルネード原理を理解することです、しかし、トルネード実装メカニズム非同期スレッドが、ファイルディスクリプタではありません、ファイルディスクリプタは、コールバックを実行し、監視するための非同期プロセスについてです。
もう一つ注意すべきは、一時停止し、目を覚ます二つのプログラムは、二つのスレッドに実装、およびトルネードが非同期に使用するファイルディスクリプタ、およびプログラムがハングしているので、それは、コルーチンとみなすことはできません我々は厳密な意味を実装したバージョンということです常に真の意味でのコルーチンに属し、トルネード自分で予定したスレッド上で目を覚まします。それを言って、それは私たちがトルネード非同期プログラミングの原則を理解して防ぐことはできません。
考えます
- コルーチンでの竜巻は、非同期、この文の右ですか?
- トルネードは、歩留まりが非同期であるこの文を右に登場しましたか?
- プログラムがハングアップが得られる方法を理解しますか?プログラムの中で竜巻とどのように非同期保留中の歩留まりを理解することは?