是不是因为协程将来可能会被抢占?或者它允许人们在关键部分使用产量(不应该鼓励 IMO)?
问问题
29660 次
2 回答
85
您使用它的原因与在线程代码中使用锁的原因相同:保护关键部分。asyncio
主要用于单线程代码,但仍然会发生并发执行(任何时候你点击 ayield from
或await
),这意味着有时你需要同步。
例如,考虑一个从 Web 服务器获取一些数据,然后缓存结果的函数:
async def get_stuff(url):
if url in cache:
return cache[url]
stuff = await aiohttp.request('GET', url)
cache[url] = stuff
return stuff
现在假设您有多个协同程序同时运行,可能需要使用的返回值get_stuff
:
async def parse_stuff():
stuff = await get_stuff("www.example.com/data")
# do some parsing
async def use_stuff():
stuff = await get_stuff("www.example.com/data")
# use stuff to do something interesting
async def do_work():
out = await aiohttp.request("www.awebsite.com")
# do some work with out
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(
parse_stuff(),
use_stuff(),
do_work(),
))
现在,假设从中获取数据url
很慢。如果两者parse_stuff
同时use_stuff
运行,每个都将受到通过网络获取的全部成本的影响stuff
。如果你用锁保护方法,你可以避免这种情况:
stuff_lock = asyncio.Lock()
async def get_stuff(url):
async with stuff_lock:
if url in cache:
return cache[url]
stuff = await aiohttp.request('GET', url)
cache[url] = stuff
return stuff
另一件需要注意的事情是,当一个协程在内部get_stuff
进行aiohttp
调用时,另一个正在等待stuff_lock
,第三个根本不需要调用get_stuff
的协程也可以运行,而不受Lock
.
显然这个例子有点做作,但希望它能让你了解为什么asyncio.Lock
有用;它允许您保护关键部分,而不会阻止其他不需要访问该关键部分的协程运行。
于 2014-09-12T02:36:05.310 回答
3
一个例子是,当您只希望某些代码运行一次,却被许多人请求时(例如,在 Web 应用程序中)
async def request_by_many():
key = False
lock = asyncio.Lock()
async with lock:
if key is False:
await only_run_once()
async def only_run_once():
while True:
if random()>0.5:
key = True
break
await asyncio.sleep(1)
于 2021-05-30T13:42:03.307 回答