Django視圖函數執行,不在主線程中,直接
loop = asyncio.new_event_loop() # 更不能loop = asyncio.get_event_loop()
會觸發
由於asyncio程序中的每一個線程都有本身的事件循環,但它只會在主線程中爲你自動建立一個事件循環。因此若是你asyncio.get_event_loop在主線程中調用一次,它將自動建立一個循環對象並將其設置爲默認值,可是若是你在一個子線程中再次調用它,你會獲得這個錯誤。相反,您須要在線程啓動時顯式建立/設置事件循環:html
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
在Django單個視圖中使用asyncio實例代碼以下(有多個IO任務時)
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任務時)
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中不依賴異步庫實現異步非阻塞
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/75046718python
https://www.cnblogs.com/zhaof/p/8490045.htmlweb
https://stackoverflow.com/questions/41594266/asyncio-with-djangodjango