Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 3.x 与协同程序的双向通信(异步IO中的状态机)_Python 3.x_Python Asyncio - Fatal编程技术网

Python 3.x 与协同程序的双向通信(异步IO中的状态机)

Python 3.x 与协同程序的双向通信(异步IO中的状态机),python-3.x,python-asyncio,Python 3.x,Python Asyncio,使用send和yield我们可以与生成器进行双向通信,并很好地实现状态机(参见下面的示例)。现在,我们不能(?)发送到asyncio协程,那么如何用asyncio协程实现状态机呢 生成器示例 def lock(): combination = [1, 2, 3] for digit in combination: a = (yield True) while a != digit: a = (yield False)

使用
send
yield
我们可以与生成器进行双向通信,并很好地实现状态机(参见下面的示例)。现在,我们不能(?)发送到asyncio协程,那么如何用asyncio协程实现状态机呢

生成器示例

def lock():
    combination = [1, 2, 3]
    for digit in combination:
        a = (yield True)
        while a != digit:
            a = (yield False)

    yield "You're in"


def main():
    l = lock()
    next(l)
    assert l.send(2) == False
    assert l.send(1) == True  # correct value 1st digit
    assert l.send(1) == False
    assert l.send(2) == True  # correct value 2nd digit
    assert l.send(2) == False
    assert l.send(3) == "You're in"  # correct value 3rd digit
与asyncio类似的东西并没有那么好。。有更好的办法吗

异步IO提案

import asyncio


class AsyncLock:
    class Message:
        def __init__(self, value):
            self.f = asyncio.Future()
            self.value = value

        def set_result(self, v):
            self.f.set_result(v)

        async def result(self):
            return await self.f

    def __init__(self, msg_q):
        self.msg_q = msg_q
        self.task = None

    async def send(self, value):
        msg = AsyncLock.Message(value)
        await self.msg_q.put(msg)
        return await msg.result()

    # all of the above to be able to do this:
    async def run(self):
        combination = [1, 2, 3]
        for digit in combination:
            msg = await self.msg_q.get()
            while msg.value != digit:
                msg.set_result(False)
                msg = await self.msg_q.get()
            msg.set_result("You're in" if digit == 3 else True)


async def amain():
    l = AsyncLock(asyncio.Queue())
    l.task = asyncio.ensure_future(l.run())

    assert await l.send(2) == False
    assert await l.send(1) == True
    assert await l.send(1) == False
    assert await l.send(2) == True
    assert await l.send(2) == False
    assert await l.send(3) == "You're in"

asyncio.get_event_loop().run_until_complete(amain())

Python3.6增加了对异步生成器()的支持,因此
async
函数现在也可以作为生成器了

#!/usr/bin/env python3.6

import asyncio

async def lock():
    combination = [1, 2, 3]
    for digit in combination:
        a = (yield True)
        while a != digit:
            a = (yield False)
    yield "You're in!"

async def main():
    coro = lock()
    await coro.asend(None)
    assert (await coro.asend(2)) == False
    assert (await coro.asend(1)) == True
    assert (await coro.asend(1)) == False
    assert (await coro.asend(2)) == True
    assert (await coro.asend(2)) == False
    assert (await coro.asend(3)) == "You're in!"
    print('Got it')

iol = asyncio.get_event_loop()
iol.run_until_complete(main())

在Python3.6之前,最好的方法是像以前一样使用消息队列。

当然。忘记异步生成器了。享受您的积分:)