简体   繁体   English

了解asyncio:异步与同步回调

[英]Understanding asyncio: Asynchronous vs synchronous callbacks

There's one very particular thing about asyncio that I can't seem to understand. 关于asyncio的一个非常特别的事情我似乎无法理解。 And that is the difference between asynchronous and synchronous callbacks. 这就是异步和同步回调之间的区别。 Let me introduce some examples. 让我介绍一些例子。

Asyncio TCP example: Asyncio TCP示例:

class EchoServer(asyncio.Protocol):

def connection_made(self, transport):
    print('connection made')

def data_received(self, data):
    print('data received: ', data.decode())

def eof_received(self):
    pass

def connection_lost(self, exc):
    print('connection lost:', exc)

Aiohttp example: Aiohttp的例子:

async def simple(request):
    return Response(text="Simple answer")

async def init(loop):
    app = Application(loop=loop)
    app.router.add_get('/simple', simple)
    return app

loop = asyncio.get_event_loop()
app = loop.run_until_complete(init(loop))
run_app(app, loop=loop)

Those two examples are very similar in functionality but they seem to be both doing it in different way. 这两个例子在功能上非常相似,但它们似乎都以不同的方式进行。 In the first example, if you want to be notified on some action, you specify a synchronous function ( EchoServer.connection_made ). 在第一个示例中,如果要通知某个操作,请指定同步函数( EchoServer.connection_made )。 However, in the second example, if you want to be notified on some action, you have to define an asynchronous callback function ( simple ). 但是,在第二个示例中,如果要通知某些操作,则必须定义异步回调函数( simple )。

I would like to ask what is the difference between these two types of callback. 我想问一下这两种类型的回调有什么区别。 I understand the difference between regular functions and asynchronous functions, but I cannot wrap my head around the callback difference. 我理解常规函数和异步函数之间的区别,但我无法理解回调差异。 For example, if I would want to write an asynchrnonous API like aiohttp is, and I would have a function that would do something and call a callback after that, how would I decide if I should demand an asynchronous function to be passed as an argument or just a regular synchronous one? 例如,如果我想编写像aiohttp那样的asynchrnonous API,并且我会有一个函数可以执行某些操作并在此之后调用回调函数,我将如何决定是否应该将异步函数作为参数传递或只是一个常规的同步?

In aiohttp example you could do asynchronous calls from simple web-handler: access to database, make http requests etc. aiohttp示例中,您可以从simple Web处理程序执行异步调用:访问数据库,发出http请求等。

In Protocol.data_received() you should call only regular synchronous methods. Protocol.data_received()您应该只调用常规同步方法。

UPD UPD

Protocol callbacks are supposed to be synchronous by design. Protocol回调应该是设计同步的。 They are very low-level bridge between sync and async. 它们是同步和异步之间的低级桥接。 You may call async code from them but it requires really tricky coding. 您可以从它们调用异步代码,但它需要非常棘手的编码。 User level asyncio API for sockets etc. are streams: https://docs.python.org/3/library/asyncio-stream.html 用于套接字等的用户级asyncio API是流: httpsasyncio

When you introduce your own callback system must likely you need asynchronous callback unless you are %100 sure why the callback will never want to call async code. 当你引入自己的回调系统时,你可能需要异步回调,除非你是%100确定回调永远不会想要调用异步代码。

Regular functions ( def ) and coroutines ( async def ) have a different signatures. 常规函数( def )和协同程序( async def )具有不同的签名。 It's hard to change a required signature, especially if your code has published as a library and you cannot control all users of your callback. 很难更改所需的签名,特别是如果您的代码已作为库发布而您无法控制回调的所有用户。

PS PS

The same is true for any public API methods. 任何公共API方法都是如此。

The hardest lesson I've learned during development of my libraries is: .close() method should be a coroutine even initially it calls sync functions only, eg socket.close() . 我在开发库时学到的最难的一课是: .close()方法应该是一个协程,即使它最初只调用同步函数,例如socket.close()

But later you perhaps will want to add a graceful shutdown which requires a waiting for current activity finishing and so on. 但是稍后您可能会想要添加一个正常关闭,这需要等待当前活动完成等等。

If your users had call your api as obj.close() now they should use await obj.close() but it's backward incompatible change! 如果你的用户已经将你的api称为obj.close()现在他们应该使用await obj.close()但它是向后不兼容的变化!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM