Python aiohttp:在满足条件时取消异步执行
我已经为一个CTF游戏编写了一个异步暴力脚本,如下所示Python aiohttp:在满足条件时取消异步执行,python,python-3.x,python-asyncio,aiohttp,Python,Python 3.x,Python Asyncio,Aiohttp,我已经为一个CTF游戏编写了一个异步暴力脚本,如下所示 async def bound_fetch(sem, session, answer): # generating url, headers and json ... async with sem, session.post(url=url, json=json, headers=headers) as response: if response.status == 200: pri
async def bound_fetch(sem, session, answer):
# generating url, headers and json ...
async with sem, session.post(url=url, json=json, headers=headers) as response:
if response.status == 200:
print('Right answer found: %s' % json['answer'])
async def run(words):
tasks = []
sem = asyncio.Semaphore(3)
async with aiohttp.ClientSession() as session:
for word in words:
task = asyncio.create_task(bound_fetch(sem=sem, session=session, answer=''.join(word)))
tasks.append(task)
print("Generated %d possible answers. Checking %s" % (len(tasks), base_url))
await asyncio.gather(*tasks)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
future = asyncio.ensure_future(run(possible_answers))
loop.run_until_complete(future)
我的参考是本教程:
我想知道在aiohttp中这是不是正确的方法,或者我是否把事情弄得太复杂了(因为我不需要处理所有的响应,只需要知道哪个响应的状态是200)?当满足条件(状态代码)时,如何取消处理
我想知道这是不是在aiohttp做这件事的正确方法
您的代码相当地道。在顶层,您可以省略asyncio.sure\u future
,只需调用asyncio.run(run(可能的答案))
当满足条件(状态代码)时,如何取消处理
您可以使用事件或未来对象并等待它,而不是使用gather
。正如您可能知道的那样,gather
不需要运行协同路由(它们与create\u task
一起按计划运行),其明确目的是等待所有协同路由完成。基于事件的同步可能如下所示:
async def bound_fetch(sem, session, answer, done):
# generating url, headers and json ...
async with sem, session.post(url=url, json=json, headers=headers) as response:
if response.status == 200:
done.set()
done.run_answer = json['answer']
async def run(words):
sem = asyncio.Semaphore(3)
done = asyncio.Event()
async with aiohttp.ClientSession() as session:
tasks = []
for word in words:
tasks.append(asyncio.create_task(bound_fetch(
sem=sem, session=session, answer=''.join(word), done=done)))
print("Generated %d possible answers. Checking %s" % (len(words), base_url))
await done.wait()
print('Right answer found: %s' % done.run_answer)
for t in tasks:
t.cancel()
好的,当条件满足时,我通过raise StopIteration
取消了执行,而不是wait asyncio.gather(*tasks)
我确实wait asyncio.wait(tasks,return\u when=asyncio.FIRST\u EXCEPTION)
。如果有人知道一种更优雅的方法,请发布一个答案:)你可能想提出一些不同于StopIteration
-因为StopIteration
是由Python使用的,所以将其用作业务例外不是一个好主意。我已经发布了一个答案,展示了如何使用事件进行同步。非常感谢您的回复。这看起来确实干净多了。我的代码编辑器抱怨asyncio.create_task()之前没有等待,但我认为这是故意的,所以它不是同步的?顺便说一句,我不确定信号灯是否有效——我在这里得到了很多连接。我可以记录一次活动连接的数量吗?嗯,看起来程序以“RuntimeError:Session is closed Task exception was never Retrieve”终止。应该是这样吗?@Phil我觉得你的IDE有点过分热情了。不过,由于你的第二句话,我修改了代码,一旦找到答案,就取消任务。这应该可以解决这两个问题,因为现在使用了create\u task
的返回值,并且在退出主协同程序之前取消了任务。(我怀疑asyncio.run
试图“完成”事件循环,该循环导致剩余任务尝试对现已关闭的会话执行某些操作。)请检查这是否解决了问题。是的,它现在可以正常工作。你能确认这里的信号灯使用正确吗?我是从Pawel的网站上复制的,我知道Dijkstra在信号量背后的理论,但我不确定我是否正确使用了它。举个例子:作者在信号量上使用acquire()和release(),这在我的code@Phil您可以使用信号量,因为async with semaphore
在进入with
块和semaphore.release()时会自动执行等待semaphore.acquire()
退出时。这比手动调用acquire
和release
更可靠,因为它将在异常或其他过早退出函数的情况下正确释放信号量。