在不设置全局策略的情况下使用替代事件循环
Using alternative event loop without setting global policy
我正在使用 uvloop
和 websockets
作为
import uvloop
coro = websockets.serve(handler, host, port) # creates new server
loop = uvloop.new_event_loop()
loop.create_task(coro)
loop.run_forever()
它工作正常,我只是想知道如果不将全局 asyncio
策略设置为 uvloop
,我是否可以 运行 一些意想不到的问题。据我所知,只要下面没有任何内容不使用全局 asyncio
方法,而是直接与传递的事件循环一起使用,那么不设置全局策略应该是有效的。对吗?
自定义事件循环应作为参数传递
如果您想在不使用 asyncio.set_event_loop(loop)
的情况下使用自定义事件循环,则必须将循环作为参数传递给每个相关的异步协程或对象,例如:
await asyncio.sleep(1, loop=loop)
或
fut = asyncio.Future(loop=loop)
您可能会注意到 asyncio
模块中的任何 coroutine/object 可能都接受此参数。
同样的事情也适用于 websockets
库,因为你 may see 来自它的源代码。所以你需要写:
loop = uvloop.new_event_loop()
coro = websockets.serve(handler, host, port, loop=loop) # pass loop as param
如果您不像这样将事件循环作为参数传递,则不能保证您的程序会正常运行。
可能,但不舒服
虽然理论上您可以在不更改策略的情况下使用某些事件循环,但我发现这非常不舒服。
几乎到处都要写loop=loop
,很烦人
不能保证某些第三方会允许您通过
作为参数循环并且不会只使用 asyncio.get_event_loop()
基于此,我建议您重新考虑您的决定并使用全局事件循环。
我知道 "unright" 使用全局事件循环可能会让人觉得,但是 "right" 方法是传递循环,因为在实践中到处都是参数更糟糕(在我看来)。
asyncio中主要有3个全局对象:
- 策略(所有线程通用)
- 默认循环(特定于当前线程)
- 运行 循环(特定于当前线程)
在 asyncio 中获取当前上下文的所有尝试都通过一个函数 asyncio.get_event_loop。
要记住的一件事是 since Python 3.6(和 Python 3.5.3+),get_event_loop
有一个特定的行为:
- 如果在循环 运行 时调用它(例如在协程中),则返回 运行 循环。
- 否则,策略将返回默认循环。
示例 1:
import uvloop
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
loop = asyncio.get_event_loop()
loop.run_forever()
这里的策略是uvloop策略。 get_event_loop
返回的循环是一个 uvloop,它被设置为该线程的默认循环。当此循环为 运行 时,它被注册为 运行 循环。
在此示例中,调用 get_event_loop()
此线程中的任何位置 returns 正确的循环。
示例 2:
import uvloop
loop = uvloop.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_forever()
这里的策略还是默认的策略。 new_event_loop
返回的循环是一个 uvloop,使用 asyncio.set_event_loop
显式将其设置为该线程的默认循环。当此循环为 运行 时,它被注册为 运行 循环。
在此示例中,调用 get_event_loop()
此线程中的任何位置 returns 正确的循环。
示例 3:
import uvloop
loop = uvloop.new_event_loop()
loop.run_forever()
这里的策略还是默认的策略。 new_event_loop
返回的循环是一个 uvloop,但它没有设置为该线程的默认循环。当此循环为 运行 时,它被注册为 运行 循环。
在此示例中,在协程 returns 右循环(运行 uvloop)中调用 get_event_loop()
。但是在协程外调用 get_event_loop()
将导致一个新的标准异步循环,设置为该线程的默认循环。
所以前两种方法都可以,但不鼓励第三种方法。
我正在使用 uvloop
和 websockets
作为
import uvloop
coro = websockets.serve(handler, host, port) # creates new server
loop = uvloop.new_event_loop()
loop.create_task(coro)
loop.run_forever()
它工作正常,我只是想知道如果不将全局 asyncio
策略设置为 uvloop
,我是否可以 运行 一些意想不到的问题。据我所知,只要下面没有任何内容不使用全局 asyncio
方法,而是直接与传递的事件循环一起使用,那么不设置全局策略应该是有效的。对吗?
自定义事件循环应作为参数传递
如果您想在不使用 asyncio.set_event_loop(loop)
的情况下使用自定义事件循环,则必须将循环作为参数传递给每个相关的异步协程或对象,例如:
await asyncio.sleep(1, loop=loop)
或
fut = asyncio.Future(loop=loop)
您可能会注意到 asyncio
模块中的任何 coroutine/object 可能都接受此参数。
同样的事情也适用于 websockets
库,因为你 may see 来自它的源代码。所以你需要写:
loop = uvloop.new_event_loop()
coro = websockets.serve(handler, host, port, loop=loop) # pass loop as param
如果您不像这样将事件循环作为参数传递,则不能保证您的程序会正常运行。
可能,但不舒服
虽然理论上您可以在不更改策略的情况下使用某些事件循环,但我发现这非常不舒服。
几乎到处都要写
loop=loop
,很烦人不能保证某些第三方会允许您通过 作为参数循环并且不会只使用
asyncio.get_event_loop()
基于此,我建议您重新考虑您的决定并使用全局事件循环。
我知道 "unright" 使用全局事件循环可能会让人觉得,但是 "right" 方法是传递循环,因为在实践中到处都是参数更糟糕(在我看来)。
asyncio中主要有3个全局对象:
- 策略(所有线程通用)
- 默认循环(特定于当前线程)
- 运行 循环(特定于当前线程)
在 asyncio 中获取当前上下文的所有尝试都通过一个函数 asyncio.get_event_loop。
要记住的一件事是 since Python 3.6(和 Python 3.5.3+),get_event_loop
有一个特定的行为:
- 如果在循环 运行 时调用它(例如在协程中),则返回 运行 循环。
- 否则,策略将返回默认循环。
示例 1:
import uvloop
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
loop = asyncio.get_event_loop()
loop.run_forever()
这里的策略是uvloop策略。 get_event_loop
返回的循环是一个 uvloop,它被设置为该线程的默认循环。当此循环为 运行 时,它被注册为 运行 循环。
在此示例中,调用 get_event_loop()
此线程中的任何位置 returns 正确的循环。
示例 2:
import uvloop
loop = uvloop.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_forever()
这里的策略还是默认的策略。 new_event_loop
返回的循环是一个 uvloop,使用 asyncio.set_event_loop
显式将其设置为该线程的默认循环。当此循环为 运行 时,它被注册为 运行 循环。
在此示例中,调用 get_event_loop()
此线程中的任何位置 returns 正确的循环。
示例 3:
import uvloop
loop = uvloop.new_event_loop()
loop.run_forever()
这里的策略还是默认的策略。 new_event_loop
返回的循环是一个 uvloop,但它没有设置为该线程的默认循环。当此循环为 运行 时,它被注册为 运行 循环。
在此示例中,在协程 returns 右循环(运行 uvloop)中调用 get_event_loop()
。但是在协程外调用 get_event_loop()
将导致一个新的标准异步循环,设置为该线程的默认循环。
所以前两种方法都可以,但不鼓励第三种方法。