用SSE把python脚本迁移部署到web端并通过浏览器监控执行状态

1、python脚本做些小工具很实用

2、通过web浏览器的方式随时随地可以操作,非常方便

3、用网页做界面,比那个老古董tkinter轻松太多了

4、最大问题是普通网页请求发出后,要等脚本执行完毕才返回结果,中间状态无法看到,而且等候时间可能很长。---->用SSE(Server Sent Events)可以轻松解决这个问题,你脚本print到屏幕上的,sse都能实时推送到网页前端。

5、使用SSE一点都不复杂,Django内置的StreamingHttpResponse就能直接推送,无需额外配置。

以下是一端运行在终端环境的脚本,其功能是执行一系列任务,期间把一些中间状态信息打印到屏幕。我们尝试把这个脚本迁移到web上。

# 为了方便理解,我把任务都用random.randint(1, 100)来模拟代替
# 此处print全部放在logger中是考虑通用性,如果看得不舒服,可以直接搜索self.log.info替换为print即可



# -*-coding: utf-8 -*-
import random,time

class Logger():
    def info(self,msg):
        print(msg)

class MyTaskProcessor():

    def __init__(self):
        self.log = Logger()

    def task1(self):
        msg1 = random.randint(1, 100)
        self.log.info(msg1)

        msg2 = random.randint(1, 100)
        self.log.info(msg2)

        result = msg1 + msg2
        return result

    def task2(self):
        msg1 = random.randint(1, 100)
        self.log.info(msg1)

        result = True if msg1>20 else False
        return result

    def task3(self):
        self.log.info("-->task2 in task3-->")
        time.sleep(1)
        result = self.task2()
        msg = "task2 success!" if result else "task2 fail!"
        self.log.info(msg)

        msg = random.randint(1, 100)
        self.log.info(msg)

        result = msg + 100
        return result

    def do_some_tasks(self):

        result = self.task1()
        self.log.info(f"result of task1:{result}")
        time.sleep(2)

        if result > 100:
            self.log.info(f"----> go to do task2 ---->")
            time.sleep(2)
            result = self.task2()
            self.log.info(f"result of task2:{result}")
        else:
            self.log.info(f"----> go to do task3 ---->")
            time.sleep(2)
            result = self.task3()
            self.log.info(f"result of task3:{result}")


if __name__=="__main__":
    worker = MyTaskProcessor()
    worker.do_some_tasks()

转换成web端操作脚本如下:

import random
import time
from django.http import StreamingHttpResponse
from django.views.generic import View


class Logger:
    def info(self, msg):
        return f"data: {msg}\n\n"


class SSEView(View):
    def get(self, request, *args, **kwargs):
        self.log = Logger()
        response = StreamingHttpResponse(self.do_some_tasks(), content_type='text/event-stream')
        response['Cache-Control'] = 'no-cache'
        return response

    def execute_task(self, task_func, *args):
        for res in task_func(*args):
            if isinstance(res, str) and res.startswith("data:"):
                yield res
            else:
                self.task_result = res

    def task1(self):
        yield self.log.info(random.randint(1, 100))
        yield self.log.info(random.randint(1, 100))
        yield random.randint(1, 100) * 2  # Simplified for example

    def task2(self):
        msg1 = random.randint(1, 100)
        yield self.log.info(msg1)
        yield msg1 > 20

    def task3(self):
        yield from self.execute_task(self.task2)
        yield self.log.info("task2 success!" if self.task_result else "task2 fail!")
        msg = random.randint(1, 100)
        yield self.log.info(msg)
        yield msg + 100

    def do_some_tasks(self):
        yield from self.execute_task(self.task1)
        time.sleep(2)  # Simulated task duration

        if self.task_result > 100:
            yield self.log.info("----> go to do task2 ---->")
            time.sleep(2)  # Simulated task switch time
            yield from self.execute_task(self.task2)
            yield self.log.info(f"result of task2: {self.task_result}")
        else:
            yield self.log.info("----> go to do task3 ---->")
            time.sleep(2)  # Simulated task switch time
            yield from self.execute_task(self.task3)
            yield self.log.info(f"result of task3: {self.task_result}")

        yield "event: close\ndata: \n\n"

核心内容是:

1、所有中间状态输出,都用yield返回 (即把print() 换成 yield)

2、对于调用自定义函数,若自定义函数中有中间状态需要输出,把自定义函数中的return换成yield

3、对于自定义函数的调用,若自定义函数中有中间状态需要输出,都加上 yield from 。并且是用self.execute_task()来调用

你可能感兴趣的:(python,前端,开发语言)