python コンピュータ - トリオでは、自分のオブジェクトが存続する限り、どのようにしてバックグラウンドタスクを実行することができますか?




アイドル 時に (2)

素晴らしい質問です。

Trioの最も奇妙で物議を醸す決定の1つは、バックグラウンドタスクの存在は実装の詳細ではなく 、APIの一部として公開されるべきだという立場をとるということです。 結局、これは正しい決定だと思いますが、それは確かに少し実験的なものであり、いくつかのトレードオフがあります。

なぜトリオはこれをしますか? 私の経験では、他のシステムではバックグラウンドタスクやスレッドの存在を抽象化できるように見えますが、実際にはあらゆる方法でリークします。プログラムをきれいに終了させようとしたり、メイン操作をキャンセルしようとするとリークしたり、呼び出した関数がバックグラウンドで実行されているのにバックグラウンドタスクが実行されているためシーケンスの問題があります。予期しない例外でクラッシュして例外が失われ、あらゆる種類の奇妙な問題が発生します。短期間ではAPIが少し面倒に感じるかもしれませんが、長期的には明示的にするとすべてが楽になります。

また、Trioライブラリを作成して使用する他の誰もが同じ問題を抱えているので、あなたのAPIがあまりにも奇妙に感じることはないでしょう:-)。

あなたが何をしようとしているのか正確にはわかりません。 たぶんそれはあなたが常にハートビート( "ping")要求に応答するためにソケットから読んでいることを望んでいるウェブソケット接続のようなものです。 1つのパターンは、次のようにすることです。

@asynccontextmanager
def open_websocket(url):
    ws = WebSocket()
    await ws._connect(url)
    try:
        async with trio.open_nursery() as nursery:
            nursery.start_soon(ws._heartbeat_task)
            yield ws
            # Cancel the heartbeat task, since we're about to close the connection
            nursery.cancel_scope.cancel()
    finally:
        await ws.aclose()

そして、あなたのユーザーはこのように使うことができます:

async with open_websocket("https://...") as ws:
    await ws.send("hello")
    ...

あなたがより興味をそそりたいと思うならば、他の選択肢はあなたのユーザーが彼ら自身の託児所で渡す1つのバージョンを専門家のために提供することでしょう:

class WebSocket(trio.abc.AsyncResource):
    def __init__(self, nursery, url):
        self._nursery = nursery
        self.url = url

    async def connect(self):
        # set up the connection
        ...
        # start the heartbeat task
        self._nursery.start_soon(self._heartbeat_task)

    async def aclose(self):
        # you'll need some way to shut down the heartbeat task here
        ...

それから、接続を1つだけ必要とし、苗床を台無しにしたくない人のために、便利なAPIも提供します。

@asynccontextmanager
async def open_websocket(url):
    async with trio.open_nursery() as nursery:
        async with WebSocket(nursery, url) as ws:
            await ws.connect()
            yield ws

ナーサリパスアプローチの主な利点は、ユーザーが多数のWebSocket接続、任意の数のWebSocket接続を開きたい場合、WebSocket管理コードの先頭で1つのナーサリを開くことができることです。それから、その中にたくさんのウェブソケットがあります。

あなたはおそらく不思議に思っているでしょう。この@asynccontextmanagerはどこにありますか。 まあ、それは3.7のstdlibに含まれています、しかしそれはまだ均一ではありません、それでこれを読んでいる時によってはあなたはまだそれを使っていないかもしれません。 それまでは、 async_generatorパッケージから@asynccontextmanagerが3.5に戻ってきます。

私はその生涯の間にタスクを生み出すクラスを書いています。 私はTrioを使っているので、保育園なしではタスクを生成できません。 私が最初に考えたことは、自分のクラスにself._nurseryして、タスクを生成できるようにすることでした。 しかし、nurseryオブジェクトはコンテキストマネージャでしか使用できないため、作成された場所と同じスコープ内で常に閉じられます。 実装の詳細なので、外部からナーサリを渡したくはありませんが、オブジェクトが存続する限り持続するタスクを生成できるようにしたいと思います(例:ハートビートタスク)。

Trioを使って、バックグラウンドタスクが長持ちするようなクラスを書くにはどうすればいいですか?


\n\r\r\n 3種類の行末があります。 re.sub中のむしろ単純な正規表現、すなわちr"\r?\n?$" 、それらをすべて捕えることができます。

(そして私たちはそれらをすべて捉えなければならない 、そうだよね?)

import re

re.sub(r"\r?\n?$", "", the_text, 1)

最後の議論では、置き換えられる回数を1に置き換え、ある程度chompを模倣します。 例:

import re

text_1 = "hellothere\n\n\n"
text_2 = "hellothere\n\n\r"
text_3 = "hellothere\n\n\r\n"

a = re.sub(r"\r?\n?$", "", text_1, 1)
b = re.sub(r"\r?\n?$", "", text_2, 1)
c = re.sub(r"\r?\n?$", "", text_3, 1)

... a == b == cTrueです。





python async-await python-trio