8

defer.execute()ツイストとイン ツイストはどう違いthreads.deferToThread()ますか?どちらも同じ引数 (関数とそれを呼び出すためのパラメーター) を取り、関数を呼び出した結果で起動される deferred を返します。

バージョンはthreads、スレッドで実行されることを明示的に示しています。ただし、deferバージョンがそうでない場合、それを呼び出すポイントは何でしょうか? リアクターで実行されるコードは決してブロックされるべきではないため、それが呼び出す関数はブロックされないようにする必要があります。その時点で、同じ結果のdefer.succeed(f(*args, **kwargs))代わりに行うことができます。defer.execute(f, args, kwargs)

4

1 に答える 1

9

defer.execute は確かに、同じスレッドでブロッキング方式で関数を実行します。関数fが例外をスローした場合にエラーバックが発生したコールバックを返すことを除いdefer.execute(f, args, kwargs)、同じことを行うという点で正しいです。一方、 defer.succeed の例では、関数が例外をスローした場合、それは外側に伝播するため、望ましくない場合があります。defer.succeed(f(*args, **kwargs)) defer.execute

わかりやすくするために、defer.execute のソースをここに貼り付けます。

def execute(callable, *args, **kw):
    """Create a deferred from a callable and arguments.

    Call the given function with the given arguments.  Return a deferred which
    has been fired with its callback as the result of that invocation or its
    errback with a Failure for the exception thrown.
    """
    try:
        result = callable(*args, **kw)
    except:
        return fail()
    else:
        return succeed(result)

つまり、defer.executeブロッキング関数の結果を deferred として受け取るためのショートカットにすぎず、これにコールバック/エラーバックを追加できます。コールバックは、通常のチェーン セマンティクスで起動されます。少しクレイジーに思えますが、Deferred はコールバックを追加する前に「起動」することができ、コールバックは引き続き呼び出されます。


あなたの質問に答えるために、なぜこれが役立つのですか?まあ、defer.executeテスト/モック化と、非同期APIを同期コードと単に統合するのに役立ちます.

defer.maybeDeferred関数を呼び出して、関数がすでに deferred を返している場合は単純にそれを返し、そうでない場合は と同様の関数も役立ちますdefer.execute。これは、呼び出されたときに deferred を提供する callable を期待する API を作成し、通常のブロッキング関数も受け入れられるようにする場合に役立ちます。

たとえば、ページを取得して処理するアプリケーションがあるとします。そして、なんらかの理由で、シングル ショットの crontab スクリプトのように、または WSGI アプリケーションでの要求に応答して、特定のユース ケースでこれを同期方式で実行する必要がありましたが、それでも同じコードベースを保持しています。コードが次のようになっている場合は、次のように実行できます。

from twisted.internet import defer
from twisted.web.client import getPage

def process_feed(url, getter=getPage):
    d = defer.maybeDeferred(getter, url)
    d.addCallback(_process_feed)

def _process_feed(result):
    pass # do something with result here

これをリアクターなしで同期コンテキストで実行するには、次のように別のゲッター関数を渡すだけです。

from urllib2 import urlopen

def synchronous_getter(url):
    resp = urlopen(url)
    result = resp.read()
    resp.close()
    return result
于 2010-09-10T17:10:51.583 に答える