是否可以在等待asyncio.sleep时更新对象的状态(即成员变量的值)?
例如,假设有一个服务器发送的计数每秒钟递增一次,客户端读取当前计数并将其存储在一个成员变量中。如果每个mod 100 it asyncio.sleeps持续10秒,那么计数器成员变量的值会在睡眠前后改变吗?例如,100岁睡觉,110岁恢复,还是100岁?
代码示例:
server.py
import asyncio
async def send_counter(reader, writer):
cnt = 0
while True:
print(f"send: {cnt!r}")
# encode counter as little endian and send
writer.write((cnt).to_bytes(4, "little"))
await writer.drain()
cnt += 1
# pace the sends
await asyncio.sleep(1)
async def main():
server = await asyncio.start_server(send_counter, "127.0.0.1", 5555)
async with server:
await server.serve_forever()
asyncio.run(main())client.py
import asyncio
class MyClass:
def __init__(self):
self._cnt = 0
@property
def count(self):
return self._cnt
@count.setter
def count(self, x):
self._cnt = x
async def do_something_then_sleep(self):
before = self._cnt
# do something here
print(f"sleeping for 10 seconds - count = {self._cnt}")
await asyncio.sleep(10)
# ideally self._cnt would reflect the latest count sent by the server
if before != self._cnt:
print(f"before and after different {before} != {self._cnt}")
async def tcp_echo_client():
reader, _ = await asyncio.open_connection("127.0.0.1", 5555)
o = MyClass()
while True:
data = await reader.read(4)
o.count = int(int.from_bytes(data, "little"))
print(f"Received: {o.count!r}")
if (o.count % 10) == 9:
await o.do_something_then_sleep()
asyncio.run(tcp_echo_client())在上面的示例中,我认为问题在于,在等待o.do_something_then_sleep时,我停止读取套接字,这是有意义的。理想情况下,我将在睡眠期间继续读取套接字,导致出现before and after different消息。
这能在单个线程上完成吗?避免引入线程、run_in_executor、新的事件循环和锁吗?也许异步中有一种机制可以用来自动读取套接字并触发数据回调,从而避免显式读取?
发布于 2021-04-28 10:59:44
是!AP (异步编程)本质上是“单线程并发”。这意味着当一个协同线处于睡眠状态时,其他协同器可以运行。
但是请注意,与多线程不同的是,如果不休眠(调用await),则不能在两个语句之间运行其他协同线程,因此在下面的示例中,变量不能在两个print语句之间进行外部更改。
import asyncio
import random
counter = 0
async def every_tenth_of_a_second():
global counter
while True:
counter += 1
await asyncio.sleep(.2 * random.random())
async def every_second():
global counter
while True:
print('counter was', counter)
counter += 1
print('counter is now', counter)
await asyncio.sleep(1)
async def async_main():
await asyncio.wait([
asyncio.create_task(every_tenth_of_a_second()),
asyncio.create_task(every_second()),
])
asyncio.run(async_main())印刷本:
counter was 1
counter is now 2
counter was 11
counter is now 12
counter was 20
counter is now 21
counter was 34
counter is now 35
counter was 44
counter is now 45
counter was 56
counter is now 57
counter was 69
counter is now 70
counter was 82
counter is now 83我建议我在AP上的博客文章作进一步解释!(:
https://stackoverflow.com/questions/67297416
复制相似问题