2017-06-16 11 views
1

私は私の問題のサンプルコードを書いています。入力メッセージは固定チャンクに分割され、意図的なランダム遅延を使用して混合されます。ただし、sleep()はブロックされており、次のタスクは実行されません。これは単一のスレッドで可能ですか、マルチスレッドに頼らなければなりませんか?Pythonでトリガされたタスクやイベントを非同期でブロックする方法を教えてください。

from random import randint 
from time import sleep 

def delay_message(split_message, delay): 
    #sleep(delay) #this blocks 
    print("Shuffled message: {} and time: {}". format(split_message, delay)) 

def main(): 
    message = raw_input('Input: ') 

    #padding 
    difference = len(message) % 5 
    message=message.ljust(len(message)+5-difference, "0") 

    for i in range(0, len(message), 5): 
     delay = randint(0, 5) 
     split_message = message[i:i+5] 
     delay_message(split_message, delay) 

if __name__ == "__main__": 
    main() 
+0

[asyncio'](https://docs.python.org/3/library/asyncio.html)をご覧ください。あなたが必要としているのは本当にノンブロッキングな睡眠であれば、それは助けになるかもしれません。 –

答えて

1

sleep実際に実行スレッドをブロックします。

geventのようなライブラリを使用して非ブロック化することは可能です。 Geventはまたtime.sleepにパッチを当て、それを非ブロッキングにして、それ自身のノンブロッキングスリープも持っています。それはまた、ソケット、時間、スレッドなど、非ブロック化するために、Python標準ライブラリ全体をパッチすることができます。documentationを参照してください。

上記の例ではそうのようなgeventと同時に協同行うことができます。

from random import randint 
from gevent import sleep, spawn, joinall 

def delay_message(split_message, delay): 
    # Gevent's sleep yields the event loop for 
    # duration of delay rather than blocking the running thread 
    sleep(delay) 
    print("Shuffled message: {} and time: {}". format(split_message, delay)) 

def main(): 
    message = raw_input('Input: ') 

    #padding 
    difference = len(message) % 5 
    message=message.ljust(len(message)+5-difference, "0") 

    greenlets = [] 
    # This will create len(message)/5 number of greenlets, 
    # which corresponds to the concurrency level. 
    # Greenlets all run under one thread so there is no CPU 
    # overhead here. 
    for i in range(0, len(message), 5): 
     delay = randint(0, 5) 
     split_message = message[i:i+5] 
     greenlets.append(spawn(delay_message, split_message, delay)) 
    # Wait for all greenlets to complete, raise any exceptions 
    joinall(greenlets, raise_error=True) 

if __name__ == "__main__": 
    main() 

制約は、彼らがイベントループおよび他のすべてのgreenletsをブロックするようCPUバウンドのタスクがgreenletsで実行することができないということです。

グリーンレットで実行されているものがソケットやジェネレータでメッセージを渡すように、入出力バインドされている限り、他のグリーンレットなど、グリーンレットが適切です。 CPUバウンドタスクの場合は、ネイティブスレッドまたは複数のプロセスを使用します。

asyncio(Py3のみ)などの代替手段があります。 GeventはPy2と3と互換性があり、ネイティブコード拡張を利用して非常に高いパフォーマンスを発揮します。

+0

ありがとう、それはとても面白いです。 CPU-boundによって、delay_messageが大量の操作を実行していたことを意味しますか?または、あなたが意味することの例を私に教えてください。 – Anderson

+0

CPUにバインドされたタスクは、CPU上でコードを実行する際にブロックされるものです。例としては、オーディオ/ビデオのエンコーディングとデコード、画像処理などがあり、基本的にCPU上で実行されるコードが含まれます。 I/Oバウンドタスクは、ネットワーク上のストリームの読み取り/書き込み、ネットワーク要求処理、ディスクI/Oなどです。ネットワーキングはスレッドでも処理できますが、実際にはCPUによって制限されていないものに対しては、CPUオーバーヘッド(CPU使用率の増加、最大並行性の低下)が発生します。そのためには、協力的なマルチタスキング(別名非同期I/O)が適しています。 – danny

+0

これは感謝しています。 Geventは 'usleep()やnanosleep()'を高度な精度で持っていません。現在の方法でこれを処理する方法はありますか?または、私が – Anderson

関連する問題