在django的View中使用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

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Django,要使用ThreadPoolExecutor线程池,你需要首先实现一个线程池对象。可以使用concurrent.futures.threadThreadPoolExecutor类来创建线程池对象。在实例化线程池对象时,你需要传入最大线程数量。下面是一个示例代码: ```python from concurrent.futures.thread import ThreadPoolExecutor class MyThread(object): def __init__(self): # 线程池 根据自己需要传入最大线程数量,我只需要一个所以传1 self.executor = ThreadPoolExecutor(1) # 用于存储期程 self.future_dict = {} # 检查worker线程是否正在运行 def is_running(self, tag): future = self.future_dict.get(tag, None) if future and future.running(): return True return False def __del__(self): self.executor.shutdown() # MyThread的生命周期是Django主进程运行的生命周期 thread = MyThread() ``` 然后,在视图函数使用线程池。下面是一个示例代码: ```python import queue from async_view_app.utils import thread from django.http import HttpResponse q = queue.Queue() def test_view(request): if request.method == "POST": print("this is test view") # 将需要异步处理的数据放入队列 task = "假装这是待处理的任务" q.put(task) # 判断worker线程是否正在运行,没有则唤醒 if not thread.is_running("worker"): future = thread.executor.submit(worker) thread.future_dict["worker"] = future return HttpResponse(1) def worker(): # 如果队列不为空,worker线程会一直从队列取任务并处理 while not q.empty(): # 每次唤醒线程执行数据库操作之前最好先关闭老的数据库连接 from django import db db.close_old_connections() # 取出任务执行 task = q.get() print(task) ``` 在worker函数,你可以根据需要对任务进行处理。这是一个基本的例子,你可以根据自己的需求进行修改或扩展。关于ThreadPoolExecutor线程池的更多方法和用法,你可以参考相关文档。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [django使用ThreadPoolExecutor实现异步视图](https://blog.csdn.net/weixin_43843008/article/details/107867051)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值