如何执行*同步*读/写asyncio传输对象

时间:2015-07-02 06:30:36

标签: python windows python-asyncio

我在Windows上使用asyncio并且引用了命名管道的传输对象:

class DataPipeHandler(asyncio.Protocol):
    def connection_made(self, trans):
        self.trans = trans # <<== this is a reference to a transport object of type _ProactorDuplexPipeTransport

loop = asyncio.get_event_loop()
server = loop.start_serving_pipe(lambda: DataPipeHandler(), r'\\.\pipe\test-pipe')

现在我想使用self.trans来同步写入,然后从命名管道读取数据。我怎么能这样做?

对我来说同步执行此操作非常重要,因为这是我正在使用管道进行的RPC调用(写一些东西并快速获取响应)我确实希望阻止偶数循环的所有其他活动直到这个“管道RPC调用”返回。 如果我没有阻止事件循环的所有其他活动,直到这个RPC调用完成,我将有不必要的副作用,因为循环将继续处理我不希望它处理的其他事件。

我想做什么(写入管道然后读取)与从事件循环线程调用urllib2.urlopen(urllib2.Request('http://www.google.com')).read()的人非常相似 - 这里所有的事件循环活动都将被阻止,直到我们得到响应来自远程http服务器。

我知道我可以调用self.trans.write(data)但这不会同步写入数据(据我所知它不会阻塞)

感谢。

编辑:在第一条评论之后,让我补充一下:

我知道我永远不应该阻止事件循环,并且我可以使用同步原语来完成我想要的东西。但是假设你有一个事件循环,它并行执行10个不同的活动,其中一个正在执行某种RPC(如上所述),所有其他9个活动都应该被阻塞,直到完成这个RPC。所以我有两个选择:

(1)按照你所建议的所有10个活动的同步添加同步原语(锁定/信号量/条件)。

(2)通过阻止写入然后阻止对管道的读取来实现此RPC。 (假设我相信管道的另一面)

我知道这不是使用事件循环的常用方法,但在我的具体情况下,我认为(2)更好。 (更简单的逻辑)

2 个答案:

答案 0 :(得分:1)

我认为你必须使用线程同步原语来确保整个循环(当前线程)被阻止。我认为最好的报价是使用线程队列和连接功能。

答案 1 :(得分:0)

@Andrew Svetlov

如你所说,asyncio Synchronization Primitives是正常的选择。

但是如何将事件循环协同程序包装和公开为同步函数API是我的问题。我不希望API使用者处理asyncio概念

更新: 找到了很酷的答案:how can I package a coroutine as normal function in event loop?