我在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)更好。 (更简单的逻辑)
答案 0 :(得分:1)
我认为你必须使用线程同步原语来确保整个循环(当前线程)被阻止。我认为最好的报价是使用线程队列和连接功能。
答案 1 :(得分:0)
@Andrew Svetlov
如你所说,asyncio Synchronization Primitives是正常的选择。
但是如何将事件循环协同程序包装和公开为同步函数API是我的问题。我不希望API使用者处理asyncio
概念
更新: 找到了很酷的答案:how can I package a coroutine as normal function in event loop?。