Mes*_*ssa 15 python semaphore python-3.x python-asyncio
当我在 Python 3.7 中运行此代码时:
import asyncio
sem = asyncio.Semaphore(2)
async def work():
async with sem:
print('working')
await asyncio.sleep(1)
async def main():
await asyncio.gather(work(), work(), work())
asyncio.run(main())
Run Code Online (Sandbox Code Playgroud)
它因运行时错误而失败:
$ python3 demo.py
working
working
Traceback (most recent call last):
File "demo.py", line 13, in <module>
asyncio.run(main())
File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/runners.py", line 43, in run
return loop.run_until_complete(main)
File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete
return future.result()
File "demo.py", line 11, in main
await asyncio.gather(work(), work(), work())
File "demo.py", line 6, in work
async with sem:
File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/locks.py", line 92, in __aenter__
await self.acquire()
File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/locks.py", line 474, in acquire
await fut
RuntimeError: Task <Task pending coro=<work() running at demo.py:6> cb=[gather.<locals>._done_callback() at /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/tasks.py:664]> got Future <Future pending> attached to a different loop
Run Code Online (Sandbox Code Playgroud)
Mes*_*ssa 28
这是因为 Semaphore 构造函数_loop在asyncio/locks.py 中设置了它的属性:
class Semaphore(_ContextManagerMixin):
def __init__(self, value=1, *, loop=None):
if value < 0:
raise ValueError("Semaphore initial value must be >= 0")
self._value = value
self._waiters = collections.deque()
if loop is not None:
self._loop = loop
else:
self._loop = events.get_event_loop()
Run Code Online (Sandbox Code Playgroud)
但是asyncio.run()开始了一个全新的循环——在asyncio/runners.py 中,它也在文档中提到:
def run(main, *, debug=False):
if events._get_running_loop() is not None:
raise RuntimeError(
"asyncio.run() cannot be called from a running event loop")
if not coroutines.iscoroutine(main):
raise ValueError("a coroutine was expected, got {!r}".format(main))
loop = events.new_event_loop()
...
Run Code Online (Sandbox Code Playgroud)
Semaphore在外部启动asyncio.run()抓取 asyncio“默认”循环,因此不能与使用asyncio.run().
Semaphore从 调用的代码启动asyncio.run()。您必须将它们传递到正确的地方,有更多的可能性如何做到这一点,例如您可以使用contextvars,但我只会举一个最简单的例子:
import asyncio
async def work(sem):
async with sem:
print('working')
await asyncio.sleep(1)
async def main():
sem = asyncio.Semaphore(2)
await asyncio.gather(work(sem), work(sem), work(sem))
asyncio.run(main())
Run Code Online (Sandbox Code Playgroud)
同样的问题(和解决方案)可能也有asyncio.Lock,asyncio.Event和asyncio.Condition。
| 归档时间: |
|
| 查看次数: |
3575 次 |
| 最近记录: |