如何在django视图中使用asyncio(协程)和ThreadPoolExecutor(多线程)
Django视图函数执行,不在主线程中,直接
loop = asyncio.new_event_loop() # 更不能loop = asyncio.get_event_loop()
会触发
RuntimeError: There is no current event loop in thread
因为asyncio程序中的每个线程都有自己的事件循环,但它只会在主线程中为你自动创建一个事件循环。所以如果你asyncio.get_event_loop在主线程中调用一次,它将自动创建一个循环对象并将其设置为默认值,但是如果你在一个子线程中再次调用它,你会得到这个错误。相反,您需要在线程启动时显式创建/设置事件循环:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
在Django单个视图中使用asyncio实例代码如下(有多个IO任务时)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | from django.views import View import asyncio import time from django.http import JsonResponse class TestAsyncioView(View): def get( self , request, * args, * * kwargs): """ 利用asyncio和async await关键字(python3.5之前使用yield)实现协程 """ start_time = time.time() loop = asyncio.new_event_loop() # 或 loop = asyncio.SelectorEventLoop() asyncio.set_event_loop(loop) self .loop = loop try : results = loop.run_until_complete( self .gather_tasks()) finally : loop.close() end_time = time.time() return JsonResponse({ 'results' : results, 'cost_time' : (end_time - start_time)}) async def gather_tasks( self ): """ 也可以用回调函数处理results task1 = self.loop.run_in_executor(None, self.io_task1, 2) future1 = asyncio.ensure_future(task1) future1.add_done_callback(callback) def callback(self, future): print("callback:",future.result()) """ tasks = ( self .make_future( self .io_task1, 2 ), self .make_future( self .io_task2, 2 ) ) results = await asyncio.gather( * tasks) return results async def make_future( self , func, * args): future = self .loop.run_in_executor( None , func, * args) response = await future return response """ # python3.5之前无async await写法 import types @types.coroutine # @asyncio.coroutine # 这个也行 def make_future(self, func, *args): future = self.loop.run_in_executor(None, func, *args) response = yield from future return response """ def io_task1( self , sleep_time): time.sleep(sleep_time) return 66 def io_task2( self , sleep_time): time.sleep(sleep_time) return 77 |
在Django单个视图中使用ThreadPoolExecutor实例代码如下(有多个IO任务时)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | from django.views import View import time from concurrent.futures import ThreadPoolExecutor, as_completed class TestThreadView(View): def get( self , request, * args, * * kargs): start_time = time.time() future_set = set () tasks = ( self .io_task1, self .io_task2) with ThreadPoolExecutor( len (tasks)) as executor: for task in tasks: future = executor.submit(task, 2 ) future_set.add(future) for future in as_completed(future_set): error = future.exception() if error is not None : raise error results = self .get_results(future_set) end_time = time.time() return JsonResponse({ 'results' : results, 'cost_time' : (end_time - start_time)}) def get_results( self , future_set): """ 处理io任务执行结果,也可以用future.add_done_callback(self.get_result) def get(self, request, *args, **kargs): start_time = time.time() future_set = set() tasks = (self.io_task1, self.io_task2) with ThreadPoolExecutor(len(tasks)) as executor: for task in tasks: future = executor.submit(task, 2).add_done_callback(self.get_result) future_set.add(future) for future in as_completed(future_set): error = future.exception() print(dir(future)) if error is not None: raise error self.results = results = [] end_time = time.time() return JsonResponse({'results': results, 'cost_time': (end_time - start_time)}) def get_result(self, future): self.results.append(future.result()) """ results = [] for future in future_set: results.append(future.result()) return results def io_task1( self , sleep_time): time.sleep(sleep_time) return 10 def io_task2( self , sleep_time): time.sleep(sleep_time) return 66 |
附tornado中不依赖异步库实现异步非阻塞
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | from tornado.web import RequestHandler from concurrent.futures import ThreadPoolExecutor class NonBlockingHandler(RequestHandler): """ 不依赖tornado的异步库实现异步非阻塞 使用 gen.coroutine 装饰器编写异步函数,如果库本身不支持异步,那么响应任然是阻塞的。 在 Tornado 中有个装饰器能使用 ThreadPoolExecutor 来让阻塞过程编程非阻塞, 其原理是在 Tornado 本身这个线程之外另外启动一个线程来执行阻塞的程序,从而让 Tornado 变得非阻塞 """ executor = ThreadPoolExecutor(max_workers = 2 ) # executor默认需为这个名字,否则@run_on_executor(executor='_thread_pool')自定义名字,经测试max_workers也可以等于1 @coroutine # 使用@coroutine这个装饰器加yield关键字,或者使用async加await关键字 def get( self , * args, * * kwargs): second = yield self .blocking_task( 20 ) self .write( 'noBlocking Request: {}' . format (second)) """ async def get(self, *args, **kwargs): second = await self.blocking_task(5) self.write('noBlocking Request: {}'.format(second)) """ @run_on_executor def blocking_task( self , second): """ 阻塞任务 """ time.sleep(second) return second |
参考 https://blog.csdn.net/qq_34367804/article/details/75046718
https://www.cnblogs.com/zhaof/p/8490045.html
https://stackoverflow.com/questions/41594266/asyncio-with-django
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!