多執行緒操作

Ligo6發表於2024-05-29

【一】threading模組開啟執行緒的兩種方式

【1】直接呼叫Thread

from threading import Thread
import time


def task(name):
    print(f'{name} is starting')
    time.sleep(3)
    print(f'{name} is ending')


def main():
    t = Thread(target=task, args=("drake",))
    # 建立執行緒的開銷非常小,幾乎程式碼執行的一瞬間執行緒就已經建立了
    t.start()


if __name__ == '__main__':
    main()
# drake is starting
# drake is ending

【2】繼承Thread父類

from threading import Thread
import time


class MyThread(Thread):
    def __init__(self, name):
        super().__init__()
        self.name = name

    def run(self):
        print(f'{self.name} is starting')
        time.sleep(3)
        print(f'{self.name} is ending')


def main():
    t1 = MyThread('dream')
    t2 = MyThread('uzi')
    t1.start()
    t2.start()


if __name__ == '__main__':
    main()

# dream is starting
# uzi is starting
# uzi is ending
# dream is ending

【三】一個程序下開啟多個執行緒和多個子程序的區別

【1】誰的開啟速度快

from threading import Thread
from multiprocessing import Process
import time


def work():
    print('hello')


def timer(func):
    def inner(*args, **kwargs):
        start_time = time.time()
        res = func(*args, **kwargs)
        print(f'函式 {func.__name__} 執行時間為:{time.time() - start_time}')
        return res

    return inner


@timer
def work_process():
    # 在主程序下開啟子程序
    t = Process(target=work)
    t.start()


@timer
def work_thread():
    # 在主程序下開啟執行緒
    t = Thread(target=work)
    t.start()


if __name__ == '__main__':
    work_thread()
    work_process()
# hello
# 函式 work_thread 執行時間為:0.0009613037109375
# 函式 work_process 執行時間為:0.03390765190124512
# hello

【2】檢視pid

from threading import Thread
from multiprocessing import Process
import os


def work():
    print(f"該程式pid:{os.getpid()}")


def work_thread():
    # 在主程序下開啟多個執行緒,每個執行緒都跟主程序的pid一樣
    t1 = Thread(target=work)
    t2 = Thread(target=work)
    t1.start()
    t2.start()


def work_process():
    # 開多個程序,每個程序都有不同的pid
    p1 = Process(target=work)
    p2 = Process(target=work)
    p1.start()
    p2.start()


if __name__ == '__main__':
    work_thread()
    # 該程式pid:100620
    # 該程式pid:100620
    work_process()
    # 該程式pid:100772
    # 該程式pid:103280

【3】同一程序內的執行緒共享該程序的資料

from threading import Thread
from multiprocessing import Process


def work():
    global num
    num = 0


def work_process():
    num = 100
    p = Process(target=work)
    p.start()
    p.join()
    print(f'程序num:{num}')  # 子程序p已經將自己的全域性的n改成了0,但改的僅僅是它自己的,檢視父程序的n仍然為100
    # 程序num:100


def work_thread():
    num = 1
    t = Thread(target=work)
    t.start()
    t.join()
    print(f'執行緒num:{num}')  # 檢視結果為1,因為同一程序內的執行緒之間共享程序內的資料
    # 執行緒num:1


if __name__ == '__main__':
    # 多程序:子程序只改自己的
    work_process()
    # 多執行緒:資料發生錯亂,同一程序內的執行緒之間共享資料
    work_thread()

【四】多執行緒併發的服務端

  • 服務端
from threading import Thread
from socket import *


# 不寫引數:預設是TCP協議
# 建立伺服器物件
server = socket()
# 繫結 IP PORT
IP = '127.0.0.2'
PORT = 8081
ADDR = (IP, PORT)
server.bind(ADDR)
# 監聽
server.listen(5)


# 將接受處理資料部分封裝成函式呼叫
def run(conn):
    while True:
        from_client = conn.recv(1024)
        # 接受的資訊為空時,會無限迴圈
        if len(from_client) == 0:
            break
        # 接收到客戶端的資訊
        print(f"這是來自客戶端的訊息:{from_client.decode()}")
        # 返回給客戶端資訊
        to_client = '你的訊息我已收到!'
        conn.send(to_client.encode())
    # 關閉連結
    conn.close()


def main():
    while True:
        # 接受連線物件和 ip port
        conn, addr = server.accept()
        t = Thread(target=run, args=(conn,))
        t.start()


if __name__ == '__main__':
    main()
  • 客戶端
from socket import *

# 不寫引數:預設是TCP協議
# 建立客戶端物件
client = socket()

# 繫結 IP PORT
IP = '127.0.0.2'
PORT = 8081
ADDR = (IP, PORT)
client.connect(ADDR)

while True:
    # 向服務端發資料
    message = input("請輸入傳送給服務端的訊息:").strip()
    client.send(message.encode())

    # 接受伺服器返回的資料
    data_from_server = client.recv(1024)
    print(data_from_server.decode())

【五】執行緒物件的屬性和方法

【1】執行緒物件的 join 方法

from threading import Thread
import time


def task(name):
    print(f'{name} is starting')
    time.sleep(3)
    print(f'{name} is ending')


def main():
    t1 = Thread(target=task, args=('drake',))
    t2 = Thread(target=task, args=('uzi',))
    t1.start()
    t2.start()
    # 主執行緒等待子程序結束之後再執行
    t1.join()
    t2.join()


if __name__ == '__main__':
    main()
    # drake is starting
    # uzi is starting
    # drake is ending
    # uzi is ending

【2】獲取當前程序的名字——current_thread

from threading import Thread, active_count, current_thread
import time


def task():
    # 獲取當前執行緒的名字
    print(f'該執行緒的名字:{current_thread().name}')
    time.sleep(2)


def main():
    t1 = Thread(target=task)
    t2 = Thread(target=task)
    t1.start()
    t2.start()
    print(f'該執行緒的名字:{current_thread().name}')


if __name__ == '__main__':
    main()
    # 該執行緒的名字:Thread - 1(task)
    # 該執行緒的名字:Thread - 2(task)
    # 該執行緒的名字:MainThread

【3】統計當前活躍的執行緒數——active_count

from threading import Thread, active_count, current_thread
import time


def task():
    # 獲取當前執行緒的名字
    print(f'該執行緒的名字:{current_thread().name}')
    time.sleep(2)


def main():
    t1 = Thread(target=task)
    t2 = Thread(target=task)
    t1.start()
    t2.start()
    # 統計當前活躍的執行緒數
    print(f'當前活躍的執行緒數:{active_count()}')
    print(f'該執行緒的名字:{current_thread().name}')


if __name__ == '__main__':
    main()
    # 該執行緒的名字:Thread - 1(task)
    # 該執行緒的名字:Thread - 2(task)
    # 當前活躍的執行緒數:3
    # 該執行緒的名字:MainThread

相關文章