asyncio 协程介绍:
- 动态添加任务:
- 方案是创建一个线程,使事件循环在线程内永久运行
- 设置守护进程,随着主进程一起关闭
- 自动停止任务
- 阻塞任务完成
- 协程池
- 队列自带阻塞机制,当队列满了后会阻塞,因此可以取代 asyncio.Semaphore()
注意
- 通过项目实战发现这种方案依旧有限制,并不是我所想要的那种协程池;
- 虽然实现了并发数限制,但是任务并不是实施加入任务队列的,而是一直堵塞在maxsize值,一旦协程池将下来再行添加任务;
- 而我想要的协程应该是任务直接加入协程池,只不过每次并发限制在maxsize,较少因队列产生的损耗;
- 下一篇将解决这个问题。
demo
import asyncio
import aiohttp
import time
import nest_asyncio
import queue
from threading import Thread
class AsyncPool(object):
"""
1. 支持动态添加任务
2. 支持自动停止事件循环
3. 支持最大协程数
"""
def __init__(self, loop=None, maxsize=0):
"""
初始化
:param loop:
:param maxsize: 默认0,不限制队列
"""
nest_asyncio.apply()
if not loop:
self.loop = asyncio.new_event_loop()
self.q = queue.Queue(maxsize)
self.loop_thread = None
if self.loop:
self.start_thread_loop()
def add(self, item=1):
"""
添加任务
:param item:
:return:
"""
self.q.put(item)
def done(self, fn):
"""
任务完成
回调函数
:param fn:
:return:
"""
if fn:
pass
self.q.get()
self.q.task_done()
def wait(self):
"""
等待任务执行完毕
:return:
"""
self.q.join()
@staticmethod
def _start_thread_loop(loop):
"""
运行事件循环
:param loop: loop以参数的形式传递进来运行
:return:
"""
asyncio.set_event_loop(loop)
loop.run_forever()
def start_thread_loop(self):
"""
运行事件循环
:return:
"""
self.loop_thread = Thread(target=self._start_thread_loop, args=(self.loop,))
self.loop_thread.setDaemon(True)
self.loop_thread.start()
def stop_thread_loop(self, loop_time=1):
"""
队列为空,则关闭线程
:param loop_time:
:return:
"""
async def _close_thread_loop():
"""
关闭线程
:return:
"""
while True:
if self.q.empty():
self.loop.stop()
break
await asyncio.sleep(loop_time)
asyncio.run_coroutine_threadsafe(_close_thread_loop(), self.loop)
def submit(self, func, callback=None):
"""
提交任务到事件循环
:param func: 异步函数对象
:param callback: 回调函数
:return:
"""
future = asyncio.run_coroutine_threadsafe(func, self.loop)
def callback_done(_future):
try:
if callback:
callback(_future)
finally:
self.done(_future)
future.add_done_callback(callback_done)
def release(self, loop_time=1):
"""
释放线程
:param loop_time:
:return:
"""
self.stop_thread_loop(loop_time)
def running(self):
"""
获取当前线程数
:return:
"""
return self.q.qsize()
async def thread_example(i):
url = "http://127.0.0.1:8080/app04/async4?num={}".format(i)
async with aiohttp.ClientSession() as session:
async with session.get(url) as res:
return await res.text()
def my_callback(future):
result = future.result()
print('返回值: ', result)
def main():
pool = AsyncPool(maxsize=10000)
for i in range(100000):
pool.add()
pool.submit(thread_example(i), my_callback)
pool.release()
pool.wait()
print("等待子线程结束...")
if __name__ == '__main__':
start_time = time.time()
main()
end_time = time.time()
print("run time: ", end_time - start_time)