use*_*759 17 python python-asyncio
是因为协程可能会在未来被抢占吗?或者它允许人们使用关键部分的收益率(不应该鼓励IMO)?
dan*_*ano 36
您使用它的原因与在线程代码中使用锁定的原因相同:保护关键部分.asyncio主要用于单线程代码,但仍然会发生并发执行(任何时候你点击yield from或await),这意味着有时你需要同步.
例如,考虑一个从Web服务器获取某些数据的函数,然后缓存结果:
@asyncio.coroutine
def get_stuff(url):
if url in cache:
return cache[url]
stuff = yield from aiohttp.request('GET', url)
cache[url] = stuff
return stuff
Run Code Online (Sandbox Code Playgroud)
现在假设您有多个并发运行的协同例程可能需要使用以下的返回值get_stuff:
def parse_stuff():
stuff = yield from get_stuff()
# do some parsing
def use_stuff():
stuff = yield from get_stuff()
# use stuff to do something interesting
def do_work():
out = yield from aiohttp.request("www.awebsite.com")
# do some work with out
tasks = [
asyncio.async(parse_stuff()),
asyncio.async(use_stuff()),
asyncio.async(do_work()),
]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
Run Code Online (Sandbox Code Playgroud)
现在,假装从中获取数据url很慢.如果两者同时parse_stuff并且use_stuff同时运行,则每个都将以通过网络获取的全部成本命中stuff.如果使用锁保护方法,则可以避免这种情况:
stuff_lock = asyncio.Lock()
def get_stuff(url):
with (yield from stuff_lock):
if url in cache:
return cache[url]
stuff = yield from aiohttp.request('GET', url)
cache[url] = stuff
return stuff
Run Code Online (Sandbox Code Playgroud)
另外需要注意的是,当一个协同程序在内部get_stuff,进行aiohttp调用,另一个stuff_lock协同程序等待时,第三个协同程序根本不需要调用get_stuff也可以运行,而不受协同程序阻塞的影响Lock.
显然这个例子有点做作,但希望它能让你知道为什么asyncio.Lock有用; 它允许您保护关键部分,而不会阻止其他协同程序运行,而不需要访问该关键部分.
小智 5
一个例子是,当您只希望某些代码运行一次,但许多代码都要求运行时(例如在网络应用程序中)
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)
Run Code Online (Sandbox Code Playgroud)