有什么作用asyncio.create_task()
?我看过文档,似乎无法理解。一些让我困惑的代码是这样的:
import asyncio
async def counter_loop(x, n):
for i in range(1, n + 1):
print(f"Counter {x}: {i}")
await asyncio.sleep(0.5)
return f"Finished {x} in {n}"
async def main():
slow_task = asyncio.create_task(counter_loop("Slow", 4))
fast_coro = counter_loop("Fast", 2)
print("Awaiting Fast")
fast_val = await fast_coro
print("Finished Fast")
print("Awaiting Slow")
slow_val = await slow_task
print("Finished Slow")
print(f"{fast_val}, {slow_val}")
asyncio.run(main())
Run Code Online (Sandbox Code Playgroud)
这给出了以下输出:
001 | Awaiting Fast
002 | Counter Fast: 1
003 | Counter Slow: 1
004 | Counter Fast: 2
005 | Counter Slow: …
Run Code Online (Sandbox Code Playgroud) 在Python中,我们await
在每个协程对象之前需要一个关键字,以便事件循环调用它。但是当我们放置 时await
,它会使调用阻塞。因此,我们最终会做与阻塞方式相同的事情。这样的用途有什么意义呢?
https://www.aeracode.org/2018/02/19/python-async-simplified/
有这个简单的代码:
import asyncio
async def main():
f = asyncio.Future()
await f
asyncio.run(main())
Run Code Online (Sandbox Code Playgroud)
协程(此处main
)可以等待 Future 对象。它基本上会被阻止,直到f
有结果或设置异常,或者直到它们被取消。
出于好奇,我想知道“这种等待是如何发生的”?我具体检查了Task.py的 Python 实现def __step()
。
在最简单的形式中,快乐的情况下,当返回的result
是 Future 时,它是:
.
.
result = coro.send(None)
.
.
blocking = getattr(result, '_asyncio_future_blocking', None)
.
.
if blocking: # So `result` is a Future with `_asyncio_future_blocking == True`
result._asyncio_future_blocking = False
result.add_done_callback(self.__wakeup, context=self._context)
self._fut_waiter = result
if self._must_cancel:
if self._fut_waiter.cancel(msg=self._cancel_message):
self._must_cancel = False
Run Code Online (Sandbox Code Playgroud)
我从本节中得到了所有其他答案(例如当它result
是裸露的yield
或CancellationError
发生时等等),除了这个! …
在这个页面上我读到了这样的内容:
asyncio 模块中的协程不受全局解释器锁或 GIL 的限制。
asyncio
但是,如果事件循环和threading
线程都在带有 GIL 的单个 Python 进程中运行,这怎么可能呢?
据我了解, GIL 对 的影响asyncio
不会像对 那样强烈threading
,因为在 的情况下threading
,解释器会切换到无用的操作,例如time.sleep()
。因此,在使用时asyncio
,建议使用asyncio.sleep()
.
据我所知,这些工具的设计目的略有不同,threading
更常用于执行 IO 绑定操作的“遗留”阻塞代码,以及asyncio
非阻塞代码。
我想知道当事件循环切换任务时,python 提供了什么保证。
据我所知async
/await
从线程显著不同之处在于基于时间分片事件循环不切换任务,这意味着除非任务收益率(await
),它会无限期地进行。这实际上很有用,因为在 asyncio 下管理临界区比使用线程更容易。
我不太清楚的是以下内容:
async def caller():
while True:
await callee()
async def callee():
pass
Run Code Online (Sandbox Code Playgroud)
在这个例子中caller
是重复的await
。所以从技术上讲,它正在屈服。但是我不清楚这是否会允许事件循环上的其他任务执行,因为它只callee
屈服于并且永远不会屈服。
也就是说,如果我callee
在“关键部分”内等待,即使我知道它不会阻塞,我是否有发生其他意外事件的风险?
我有这个 Cython 代码(简化):
class Callback:
async def foo(self):
print('called')
cdef void call_foo(void* callback):
print('call_foo')
asyncio.wait_for(<object>callback.foo())
async def py_call_foo():
call_foo(Callback())
async def example():
loop.run_until_complete(py_call_foo())
Run Code Online (Sandbox Code Playgroud)
但是会发生什么:我得到RuntimeWarning: coroutine Callback.foo was never awaited
. 而且,事实上,它从未被调用过。然而,call_foo
被称为。
知道发生了什么/如何让它真正等待Callback.foo
完成吗?
在上面的示例中,缺少一些重要的细节:特别是,从call_foo
. 真正的项目设置是这样的:
有规则的 Bison 解析器。规则引用了特制的结构,我们称之为ParserState
. 此结构包含对回调的引用,当规则匹配时,解析器会调用回调。
在 Cython 代码中,有一个类,我们称之为Parser
,包的用户应该扩展它以制作他们的自定义解析器。这个类有一些方法,然后需要从ParserState
.
解析应该是这样发生的:
async def parse_file(file, parser):
cdef ParserState state = allocate_parser_state(
rule_callbacks,
parser,
file,
)
parse_with_bison(state)
Run Code Online (Sandbox Code Playgroud)回调具有一般形状:
ctypedef void(callback*)(char* text, void* parser)
Run Code Online (Sandbox Code Playgroud)
我不得不承认我不知道具体是如何asyncio
实现的await …
您好,我是 Python 新手,正在尝试使用 Detrous 制作的 Dark Sky Python API。当我运行演示代码时,出现错误:
forecast = await darksky.get_forecast(
^
SyntaxError: 'await' outside function
Run Code Online (Sandbox Code Playgroud)
此错误源于:
forecast = await darksky.get_forecast(
latitude, longitude,
extend=False, # default `False`
lang=languages.ENGLISH, # default `ENGLISH`
units=units.AUTO, # default `auto`
exclude=[weather.MINUTELY, weather.ALERTS] # default `[]`
)
Run Code Online (Sandbox Code Playgroud)
我不太确定如何解决这个问题,我正在使用 python 3。
谢谢
据我了解,目的是同时asyncio.gather
运行其参数,并且当协程执行等待表达式时,它为事件循环提供了安排其他任务的机会。考虑到这一点,我惊讶地发现以下代码片段忽略了.asyncio.gather
import asyncio
async def aprint(s):
print(s)
async def forever(s):
while True:
await aprint(s)
async def main():
await asyncio.gather(forever('a'), forever('b'))
asyncio.run(main())
Run Code Online (Sandbox Code Playgroud)
据我了解,会发生以下情况:
实际上,这不是我所观察到的。相反,整个程序相当于while True: print('a')
. 我发现非常有趣的是,即使对代码进行微小的更改似乎也会重新引入公平性。例如,如果我们使用以下代码,那么我们会在输出中得到大致相等的“a”和“b”混合。
async def forever(s):
while True:
await aprint(s)
await asyncio.sleep(1.)
Run Code Online (Sandbox Code Playgroud)
验证它似乎与我们在无限循环中和在无限循环外花费的时间没有任何关系,我发现以下更改也提供了公平性。
async def forever(s):
while True:
await aprint(s)
await asyncio.sleep(0.)
Run Code Online (Sandbox Code Playgroud)
有谁知道为什么会发生这种不公平现象以及如何避免它?我想,当有疑问时,我可以主动在各处添加一个空的睡眠语句,并希望这足够了,但对我来说,为什么原始代码的行为不符合预期,这对我来说非常不明显。
以防万一,因为 asyncio 似乎已经经历了相当多的 API 更改,我在 Ubuntu 机器上使用 Python 3.8.4 的普通安装。
引入async for
和的意义async with
何在?我知道这些陈述有 PEP,但它们显然是为语言设计者准备的,而不是像我这样的普通用户。将不胜感激补充示例的高级理由。
我自己做了一些研究并找到了这个答案:
该
async for
和async with
语句必要的,因为你会打破yield from/await
与裸链for
和with
报表。
作者没有举例说明链条是如何断裂的,所以我仍然很困惑。此外,我注意到 Python 有async for
and async with
,但没有async while
and async try ... except
。这听起来很奇怪,因为和分别是for
和 的with
语法糖。我的意思是,考虑到后者是前者的构建块,它们的版本不会允许更大的灵活性吗?while
try ... except
async
还有另一种答案讨论async for
,但它仅覆盖它是什么并不对,并没有说太多关于它是什么。
作为奖励,async for
和async with
语法糖?如果是,它们的详细等效形式是什么?
我有一个使用 asyncio 和 websockets 的 python 套接字服务器。当 websocket 处于活动状态时,100 多个设备将连接并保持连接等待命令/消息。
有两个线程,第一个线程接受连接并将其详细信息添加到全局变量中,然后等待来自设备的消息:
async def thread1(websocket, path):
client_address = await websocket.recv()
CONNECTIONS[client_address] = websocket
async for message in websocket:
... do something with message
start_server = websockets.serve(thread1, host, port)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.ensure_future(thread2())
asyncio.get_event_loop().run_forever()
Run Code Online (Sandbox Code Playgroud)
第二个线程处理一些用户数据,一旦需要发送命令,它就会访问全局变量以获取 websocket 信息:
thread2()
...some data processing
soc = CONNECTIONS[ipaddress]
await soc.send("some message")
Run Code Online (Sandbox Code Playgroud)
我的问题:允许另一个线程发送消息的最佳方式是什么?
我可以使用线程锁定和仅用于处理该数据的函数来保留全局变量safe
,但是全局变量并不理想。我无法在线程之间发送信息,因为 thread1 正在stuck
等待接收消息。
python ×10
async-await ×5
asynchronous ×2
python-3.x ×2
coroutine ×1
cython ×1
darksky ×1
future ×1
gil ×1
websocket ×1