1

このテーマに関するすべてのドキュメントを読みましたが、Pythonコルーチンの概念全体を十分に理解して、やりたいことを実装することができないようです。

私にはバックグラウンドタスクがあり(ランダムなファイルを生成しますが、それはそれほど重要ではありません)、無限ループでこれを実行します(これはウォッチャーです)。

このバックグラウンドタスクを可能な限り最も効率的な方法で実装したいと思います。マイクロスレッド(別名コルーチン)はそれを実現するための良い方法だと思いましたが、まったく機能させることができません(バックグラウンドタスクが実行されます)。またはプログラムの残りの部分のいずれかですが、同時に両方ではありません!)。

コルーチンを使用して実装されたバックグラウンドタスクの簡単な例を教えてもらえますか?それとも、コルーチンをその目的に使用できると誤解していますか?

Python2.7ネイティブコルーチンを使用しています。

私は、特にDBMSとAdaの並行性に精通しているので、基本的な原則についてはよく知っていますが、私にとって非常に新しいコルーチンとしてのジェネレーターの概念には慣れていません。

/編集:これが私のコードのサンプルですが、これをもう一度強調する必要がありますが、機能していません:

@coroutine
def someroutine():
    with open('test.txt', 'a') as f:
        f.write('A')
    while True:
        pass
    yield 0

@coroutine
def spawnCoroutine():
    result = yield someroutine()

    yield result

routine = spawnCoroutine()
print 'I am working in parallel!'

# Save 'A' in the file test.txt, but does not output 'I am working in parallel!'

注:@coroutineは、DavidBeazleyによって提供されたcoroutine.pyのデコレータです。

/最終編集とソリューションの要約

あいまいに見えたので、私の質問は閉じられました。これは、実際ところ、私の質問の目的です。スレッド化とマルチプロセッシングでのコルーチンの使用法を明確にすることです。

幸いなことに、恐ろしい制裁が発生する前に、良い回答が提出されました!

上記の質問への答えを強調するために:いいえ、コルーチンとの並列処理がないため、Pythonのコルーチン(またはブルーレット/グリーンレット)を使用して、独立した、潜在的に無限のCPUバウンドタスクを実行することはできません。

これが私を最も混乱させたものです。確かに、並列処理は並行性のサブセットであるため、Pythonでのコルーチンの現在の実装では並行タスクは許可されますが、並列タスクは許可されないことはかなり混乱します。この動作は、Adaなどの並行プログラミング言語のタスクの概念と明確に区​​別する必要があります。

また、Pythonのスレッドは、I / Oの待機時にコンテキストを切り替えるという点でコルーチンに似ているため、独立したCPUバウンドタスクの候補としては適していません(David BeazleyのGILの理解を参照)。

私が現在使用している解決策は、multiprocessingモジュールでサブプロセスを生成することです。バックグラウンドプロセスの生成は重いですが、何も実行しないよりはましです。これには、計算の分散を可能にするという利点もあります。

別の方法として、Google App Engineには、マルチプロセッシングの興味深い代替手段を提供できるdeferredモジュールbackground_threadモジュールがあります(たとえば、 typhoonaeなどのGoogle App Engine APIを実装するライブラリの一部を使用することにより、わかりませんが彼らはまだこれらのモジュールを実装しています)。

4

2 に答える 2

3

使用している(簡単な)ライブラリを見ると、「バックグラウンドで」coroutine.pyどのように機能するかを示す例が含まれています。grepコードと例には2つの違いがあります。

  1. grepyield作業中に繰り返しsを実行します。実際、 yield1行に1回です。これを行う必要があります。そうしないと、コルーチンが完了するまで実行する機会があります。

  2. メインコードはsendgrepコルーチンを繰り返し呼び出します。これも1行に1回です。これを行う必要があります。そうしないと、コルーチンが呼び出されません。

これは、可能な限り些細なケースです。単一のコルーチンと、その1つのコルーチンを無条件に駆動する些細なディスパッチャーです。

例を機能するものに変換する方法は次のとおりです。

@coroutine
def someroutine():
    with open('test.txt', 'a') as f:
        yield
        f.write('A')
    while True:
        yield
    yield 0

routine = someroutine()
print 'I am working in parallel!'
routine.send()
print 'But only cooperatively...'
routine.send()

等々。

しかし、通常はこれを行いたくありません。このgrep例の場合、コルーチンとメインドライバーは、コンシューマーとプロデューサーとして明示的に協力しているため、直接結合は完全に理にかなっています。独立してスケジュールしたい完全に独立したタスクがいくつかあります。

そのためには、自分でスレッドを作成しようとしないでください。協調スレッドが必要な場合は、既成のディスパッチャー/スケジューラーを使用します。すべてのタスクに加える必要がある唯一の変更は、yield時間を効果的に共有するのに十分な頻度で呼び出しを行うことです。

スレッドが協調的であることさえ気にしない場合は、threadingまたはを使用するだけで、 smultiprocessingは必要ありません。yield

def someroutine():
    with open('test.txt', 'a') as f:
        f.write('A')
    while True:
        pass
    return 0

routine = threading.Thread(someroutine)
print 'I am working in parallel!'

PS、コメントの1つで述べたように、http://www.dabeaz.com/coroutines/index.htmlまたは同等のものを使用したことがない場合は、実際にそれを実行して、質問があれば戻ってきてください。理解できないコードを記述して、なぜそれが機能しないのかを尋ねる代わりに、途中で見つけてください。パート4(おそらくそれ以前)に到達すると、最初の質問がばかげた理由がわかると思います。

于 2012-11-14T22:18:19.623 に答える
1

Trueの場合:合格

エンドレスループ。

したがって、その後はyeldを実行しません。実際、その機能の本当の終わり、それ以降のすべては純粋に役に立たない装飾です。

そして、someroutineはyeldする前にSTUCKを取得するので(しゃれを意図した;))、yeld someroutine()もyeldしません。

したがって、スクリプトは忙しく何もしません。(無限の空のループ)。

于 2012-11-14T20:43:41.687 に答える