asyncio를 사용하여 멀티스레드 비동기 멀티태스킹 인터페이스 작업 구현

b4e0f5fffa7dcf7e67f7c6ccfcaed65b.gif

머리말

최근에는 윈도우 클라이언트에서 시작되는 비동기 멀티태스킹 요청을 요구하는 프로젝트가 있는데, 장기간의 백그라운드 작업이 포그라운드 작업을 차단하는 것을 방지하기 위해 멀티 스레드를 시작하여 UI 메인 인터페이스 이벤트 루프와 asyncio 백그라운드 비동기 작업 이벤트 루프.

지원 라이브러리 소개

1. 비동기 코루틴 라이브러리 asyncio

asyncio코루틴을 사용하여 이벤트 루프를 구현하여 비동기 작업의 효과를 얻으세요.

pip install asyncio

코루틴은 데코레이터를 사용하여 @asyncio.coroutine비동기 작업을 표시하고 yield from비동기 작업이 완료될 때까지 기다립니다. ~에

  • @asyncio.coroutine === 비동기

  • ===에서 산출

키워드가 도입된 이후 async/await코드 구현이 훨씬 더 우아해졌습니다.

2. 인터페이스 라이브러리 wxPython

wxPython은 Python 프로그래밍 언어를 위한 크로스 플랫폼 GUI 툴킷 입니다. 이를 통해 Python 프로그래머는 강력하고 강력한 그래픽 사용자 인터페이스를 사용하여 프로그램을 간단하고 쉽게 만들 수 있습니다. 이는 C++로 작성된 인기 있는 wxWidgets 크로스 플랫폼 라이브러리의 GUI 구성 요소를 래핑하는 Python 확장 모듈 세트로 구현됩니다.

pip install wxpython

특히 windows다음 독특하고 멋진 창 효과를 많이 얻을 수 있습니다. 자세한 내용은 wxDemo예제를 실행하여 참조할 수 있습니다.

# 运行 python目录下/Scripts/wxdemo.exe
C:\ProgramData\Anaconda3\envs\ctrip_code36\Scripts>wxdemo.exe
162dd50a9996c146ca9b33133844684a.png

멀티태스킹 코루틴

1. 비동기 작업 생성

먼저 비동기 작업을 생성하고, 작업 기간을 무작위로 지정하고, 작업 시작 시간과 종료 시간을 기록합니다.

async def AsyncTask(self, name):
    t = random.randint(1, 5)
    self.log('Start %s: %.8f, duration %ds' % (name, time.time() - self.start, t))
    await asyncio.sleep(t)  # 模拟长时间后台操作
    self.log('End %s: %.8f' % (name, time.time() - self.start))
    return name

async 비동기 함수를 정의하는 키워드는 await작업이 반환될 때까지 기다립니다. 여기서는 asyncio.sleep()실제 작업을 시뮬레이션하는 데 사용됩니다 IO.

비동기 작업이 끝난 후 트리거될 콜백 함수를 설정합니다.

def task_callback(self, task):
    time.sleep(1)
    self.log('Callback %s: %.8f' % (task.result(), time.time() - self.start))

2. 창 인터페이스 구축

비동기 작업을 트리거하는 버튼과 현재 작업 상태를 표시하는 정적 텍스트가 포함된 간단한 창을 그립니다.

class MyFrame(wx.Frame):
    def __init__(
            self, parent, ID, title, pos=wx.DefaultPosition,
            size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE
    ):
        wx.Frame.__init__(self, parent, ID, title, pos, size, style)
        panel = wx.Panel(self, -1)

        self.start = time.time()  # 记录初始时间戳

        btn = wx.Button(panel, -1, "启动异步任务", size=(100, 30))
        btn.SetPosition((20, 20))

        txt = wx.StaticText(panel, -1, "任务未运行", (200, 40))
        txt.SetPosition((30, 70))
        self.txt = txt

        self.Bind(wx.EVT_BUTTON, self.OnButton, btn)
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
3e23eee0462cf73c2bf2f551407c0a3b.png

3. 스레드 생성

이벤트 루프를 획득하고 asyncio, 독립 스레드를 시작하고, 기본 인터페이스 이벤트를 격리합니다.

def OnButton(self, evt):
    async_loop = asyncio.get_event_loop()
    if not async_loop.is_running():
        threading.Thread(target=self._asyncio_thread, args=(async_loop,)).start()
    return

4. 메인 작업 생성

task1독립적인 하위 작업과 동시 하위 작업 세트 task2포함된 기본 작업을 설정합니다 task3.

  • 먼저 주요 작업이 Master task시작됩니다.

  • 5초 하위 작업이 시작됩니다 task1.

  • task2완료 후 5초 하위 작업 과 4초 하위 작업이 동시에 시작되고 task3콜백 함수가 설정되었습니다.

  • 그런 다음 task3작업 시간이 짧고 먼저 완료되며 작업 콜백이 트리거됩니다.

  • 그런 다음 task2완료되고 해당 콜백이 실행됩니다.

  • 마지막으로 Master task종료합니다.

def _asyncio_thread(self, async_loop):
    self.log('Start %s: %.8f' % ('Master task', time.time() - self.start))
    asyncio.set_event_loop(async_loop)

    print('异步单任务', 'task1')
    task = asyncio.ensure_future(self.AsyncTask('task1'))
    async_loop.run_until_complete(task)

    print('异步多任务并发', 'task2', 'task3')
    tasks = []
    task = asyncio.ensure_future(self.AsyncTask('task2'))
    task.add_done_callback(self.task_callback)
    tasks.append(task)  # 将多个任务对象装在到一个任务列表中

    task = asyncio.ensure_future(self.AsyncTask('task3'))
    task.add_done_callback(self.task_callback)
    tasks.append(task)

    async_loop.run_until_complete(asyncio.wait(tasks))

    self.log('End %s: %.8f' % ('Master task', time.time() - self.start))
    return
694798e38abf429d5ff5dbb765816de4.png

프로세스를 요약하면 다음과 같습니다.

  • asyncio이벤트 루프를 얻으세요 async_loop = asyncio.get_event_loop();

  • 스레드를 실행하고 async_loop이를 하위 스레드에 삽입합니다.

  • 하위 스레드에서 이벤트 루프를 설정하고 기본 인터페이스 이벤트 루프를 분리합니다.asyncio.set_event_loop(async_loop);

  • asyncio.ensure_future비동기 작업을 구성하는 데 사용됩니다 .

  • 콜백 기능 설정을 사용하세요 add_done_callback.

  • 비동기 기능을 실행하는 데 사용됩니다 async_loop.run_until_complete.

동시 멀티태스킹 코루틴

하위 작업 간에 종속성이 없으면 동시 실행을 사용하여 프로그램의 실행 효율성을 크게 향상시킬 수 있습니다.

1d3575cf30a2a99b2ec1b2f85220de7c.png

1. 여러 비동기 작업 만들기

def OnButton(self, evt):
    async_loop = asyncio.get_event_loop()
    if not async_loop.is_running():
        t = threading.Thread(target=self._asyncio_thread, args=(async_loop,))
        t.start()

    for i in range(5):
        asyncio.run_coroutine_threadsafe(self.AsyncTask('task%d' % i), async_loop)

2. 스레드 생성

def _asyncio_thread(self, async_loop):
    asyncio.set_event_loop(async_loop)
    async_loop.run_forever()

3. 이벤트 루프 종료

스레드 내의 스레드가 시작되므로 프로그램을 닫을 때 프로그램이 원활하게 종료되도록 해당 정리 작업을 수행해야 한다는 점은 주목할 가치 async_looprun_forever()있습니다 call_soon_threadsafe(async_loop.stop).

def OnCloseWindow(self, evt):
    async_loop = asyncio.get_event_loop()
    async_loop.call_soon_threadsafe(async_loop.stop)
    self.Destroy()
539d2ff42c6fbe9a1555ec34843bfbc1.png

추가 읽기

더 자세한 내용은 기본 원칙부터 디자인 패턴까지 매우 자세히 설명되어 있는 "Async IO in Python: A Complete Walkthrough"를 참조하세요.

https://realpython.com/async-io-python/

소스코드 다운로드

ff7f529709a6c88f89d6b33937c78ef4.png이 문제의 전체 소스 코드는 공개 계정 "Deep Awakening"에서 찾을 수 있으며 백그라운드에서 "asyncio"라고 답하여 다운로드 링크를 얻을 수 있습니다.

추신: 늦은 밤에 코딩할 때 코더는 본질적으로 커피를 코드로 변환하는 생물입니다. 하지만 커피를 너무 많이 마시는 것은 몸이 견디지 못해서 최근에는 커피를 끊고 자몽차에 푹 빠져들게 되었습니다.

헝쇼우탕 허니자몽차 추천드려요 하나 사시면 하나 공짜로 드려요 한국것보다 맛이 좋아요 그런데 국산제품 지지합니다.

7f464902a2b5b5d5406f0ed2dcf2fb8c.gif

추천

출처blog.csdn.net/weixin_47479625/article/details/120793384