天天看點

Python3 協程、線程、程序example & 對比概述例程

概述

除了一般程式設計語言都具備的線程、程序,python還有一種‘輕量級’的線程——協程。

程序

不必贅述,和其他語言類似。

線程

python的線程是一個奇葩的存在,不同于其他語言。随着硬體技術的高速發展,各CPU廠商在核心頻率上的比賽已經被多核所取代。為了更好的利用多核優勢,随之衍生出了多線程程式設計,python自然也不能免俗。但是多線程帶來的問題是線程間資料一緻性和狀态同步,最簡單的就是加一把鎖,于是産生了一把名叫GIL的超級鎖。這把鎖的存在,使得python的多線程事實上依然隻是單線程,因為GIL限制了同一時刻,隻能有一個線程拿到鎖。正因為GIL的存在,導緻了python的多線程不是并行,隻能算并發,性能極低。

協程

協程是一種輕量級的線程。與線程的差別是,線程是由作業系統排程切換,而協程有python程式自己控制排程。

Python3 協程、線程、程式example & 對比概述例程

例程

多程序

關鍵詞:程序池、程序間通信、信号捕捉

#!/usr/bin/python3

import os
import signal
import time
from multiprocessing import Pool, Queue


# 建立一個queue用于程序間通信
chan = Queue()


def producer():
    while 1:
        now = time.time()
        print('producer time: {}'.format(now))
        # 入隊
        chan.put_nowait(now)
        time.sleep(1)


def consumer():
    while 1:
        if not chan.empty():
            # 出隊
            now = chan.get_nowait()
            print('consumer time: {}'.format(now))


def sig_handler(signum, frame):
    pid = os.getpid()
    ppid = os.getppid()
    print('[{}][{}]signal {} received, program exit...'.format(pid, ppid, signum))
    exit(0)


if __name__ == '__main__':
    signal.signal(signal.SIGINT, sig_handler)
    signal.signal(signal.SIGHUP, sig_handler)
    signal.signal(signal.SIGTERM, sig_handler)
    # 建立可容納兩個子程序得程序池
    pools = Pool(processes=2)
    try:
        pools.apply_async(producer, args=())
        pools.apply_async(consumer, args=())
    except Exception as e:
        print('exception {} capture, program exit...'.format(e))
        exit(1)

    while 1:
        pass
           

多線程

關鍵詞:多線程、線程間通信、信号捕捉

#!/usr/bin/python3

import os
import signal
import time
import _thread
import queue


# 建立一個queue用于線程間通信
chan = queue.Queue()


def producer():
    while 1:
        now = time.time()
        print('producer time: {}'.format(now))
        # 入隊
        chan.put_nowait(now)
        time.sleep(1)


def consumer():
    while 1:
        if not chan.empty():
            # 出隊
            now = chan.get_nowait()
            print('consumer time: {}'.format(now))


def sig_handler(signum, frame):
    pid = os.getpid()
    ppid = os.getppid()
    print('[{}][{}]signal {} received, program exit...'.format(pid, ppid, signum))
    exit(0)


if __name__ == '__main__':
    signal.signal(signal.SIGINT, sig_handler)
    signal.signal(signal.SIGHUP, sig_handler)
    signal.signal(signal.SIGTERM, sig_handler)

    try:
        _thread.start_new_thread(producer, ())
        _thread.start_new_thread(consumer, ())
    except:
        print('Error: unable to start thread')

    while 1:
        pass

           

多協程

關鍵詞:協程、協程間通信、協程排程

在編寫協程時需要注意,協程需要程式自己控制切換,也就是代碼中調用

await asyncio.sleep(1)

,本質是讓producer協程陷入睡眠,交出CPU使用權,然後consumer獲得執行時機,輪換交複。

#!/usr/bin/python3

import os
import signal
import time
import asyncio


# 建立一個queue用于協程間通信
chan = asyncio.Queue()


async def producer():
    while 1:
        now = time.time()
        # 入隊
        await chan.put(now)
        print('producer time: {}'.format(now))
        await asyncio.sleep(1)


async def consumer():
    while 1:
        # 出隊
        now = await chan.get()
        print('consumer time: {}'.format(now))
        await asyncio.sleep(1)


def sig_handler(signum, frame):
    pid = os.getpid()
    ppid = os.getppid()
    print('[{}][{}]signal {} received, program exit...'.format(pid, ppid, signum))
    exit(0)


if __name__ == '__main__':
    signal.signal(signal.SIGINT, sig_handler)
    signal.signal(signal.SIGHUP, sig_handler)
    signal.signal(signal.SIGTERM, sig_handler)

    tasks = [asyncio.ensure_future(producer()),
             asyncio.ensure_future(consumer())]
    loop = asyncio.get_event_loop()
    try:
        loop.run_until_complete(asyncio.wait(tasks))
    except Exception as e:
        for task in tasks:
            task.cancel()
        loop.stop()
        loop.run_forever()
    finally:
        loop.close()