天天看點

Python3簡單實作多任務(線程/協程篇)線程多任務實作1:直接使用Thread建立線程線程多任務實作2:定義類繼承threading.Thread,然後重寫run方法(run方法相當于功能函數)協程多任務實作1:gevent(使用簡單,推薦!需要pip安裝gevent)

寫在前面

  • 上一篇文章[Python3簡單實作多任務(多程序篇)]已經介紹了python多程序實作多任務的簡單實作方法;
  • 這次講一講python建立多任務另外兩種常見的方式:
  • 協程和線程

線程多任務實作1:直接使用Thread建立線程

from threading import Thread
import threading
import os
import time
import random

def not_know(thread_num):
    
    print("第%d線程吟唱:不知天上宮阙"%(thread_num))
    time.sleep(random.random())
    print("第%d線程吟唱:今夕是何年"%(thread_num))
    time.sleep(random.random())
    print("第%d号線程:<吟唱古詩>任務結束..."%(thread_num))

def main():
    for i in range(1, 6):
        num = len(threading.enumerate())
        print("目前線程數為:%d"%num)
        t = Thread(target=not_know, args=(i,))
        t.start()
        time.sleep(0.8)

if __name__ == "__main__":
    print("--->主函數開始運作<---")
    main()
    print("--->主函數運作完畢<---")
           

線程多任務實作2:定義類繼承threading.Thread,然後重寫run方法(run方法相當于功能函數)

from threading import Thread
import threading
import os
import random
import time

class the_cosmetic(threading.Thread):
    def __init__(self, num):
        self.num = num
        # 一定要記得調用父類構造方法
        threading.Thread.__init__(self)

    def run(self):
        print("-->第%d線程開始執行<--"%self.num)
        time.sleep(random.random())
        print("%d最有效的化妝品是什麼?"%self.num)
        time.sleep(random.random())
        print("%dPhotoshop是最好的化妝品!"%self.num)
        time.sleep(random.random())
        print("-->第%d線程執行完畢<--"%self.num)

def main():
    print("-------->開始建立線程<--------")

    for i in range(1, 6):
        t = the_cosmetic(i)
        t.start()

    print("-------->線程建立完畢<--------")

if __name__ == "__main__":
    main()
           

協程多任務實作1:gevent(使用簡單,推薦!需要pip安裝gevent)

sudo pip3 install gevent

import time
import random
import gevent
from gevent import monkey

monkey.patch_all()

def peach(name):
    for i in range(1, 6):
        start_time = time.time()
        time.sleep(random.random())
        end_time = time.time()
        # 使用 round() 控制小數點位數!
        print("%s産出第%s個桃子,耗時%s"%(name, i, round(end_time - start_time, 2)))

def apple(name):
    for i in range(1, 8):
        start_time = time.time()
        time.sleep(random.random())
        end_time = time.time()
        print("%s産出第%s個蘋果,耗時%s"%(name, i, round(end_time - start_time, 2)))

def main():
    # 注意:下面的語句,沒有等号! 沒有等号! 沒有等号!
    gevent.joinall([
        gevent.spawn(peach,"LI"),
        gevent.spawn(apple,"HO"),
        ])

if __name__ == "__main__":
    main()

           

協程多任務實作2:yield實作協程(yield最底層,最靈活,是python自帶的子產品)

import time

def to_activate():
    yield
    print("吃早飯")
    print("讀文檔")
    yield
    print("吃中午飯")
    print("寫程式")
    yield
    print("吃晚飯")
    print("解bug")

def to_sleep():
    yield
    print("午睡")
    yield
    print("晚休")

def main():
    print("程式員的一天")
    activate = to_activate()
    sleep = to_sleep()

    # 利用yield開始在兩個函數間跳轉
    next(activate)
    next(sleep)
    next(activate)
    next(sleep)
    next(activate)

    print("程式員的一天結束了")



if __name__ == "__main__":
    main()


           

協程多任務實作3:greenlet實作協程(子產品須通過pip單獨安裝,個人感覺這個子產品封裝的并不夠好,是以放到最後,僅供了解)

sudo pip3 install greenlet

import time
from greenlet import greenlet

activate = None
sleep = None

def to_activate():
    print("吃早飯")
    print("讀文檔")
    sleep.switch()
    print("吃中午飯")
    print("寫程式")
    print("吃晚飯")
    print("解bug")

def to_sleep():
    print("午睡")
    activate.switch()
    print("晚休")

def main():
    global activate
    global sleep
    print("程式員的一天")
    activate = greenlet(to_activate)
    sleep = greenlet(to_sleep)

    #從activate開始執行
    activate.switch()
    print("程式員的一天結束了")



if __name__ == "__main__":
    main()

           

小結

  • 線程與程序相比,占用資源更少,但線程依賴于程序,一個程序可以有多個線程,程序完成任務依賴于内部的線程;
  • 協程解決了線程之間争用資源引發的資源浪費,是以協程比線程占用的資源更少.