1. 程式人生 > >Python 基礎之-進程、線程

Python 基礎之-進程、線程

don 動態 銷毀 %s 解釋 定義 進程控制 imp fork

進程與線程

什麽是進程

程序並不能單獨運行,只有將程序裝載到內存中,系統為它分配資源才能運行,而這種執行的程序就稱之為進程。程序和進程的區別就在於:程序是指令的集合,它是進程運行的靜態描述文本;進程是程序的一次執行活動,屬於動態概念。

在多道編程中,我們允許多個程序同時加載到內存中,在操作系統的調度下,可以實現並發地執行。這是這樣的設計,大大提高了CPU的利用率。進程的出現讓每個用戶感覺到自己獨享CPU,因此,進程就是為了在CPU上實現多道編程而提出的。

有了進程為什麽還要線程?

進程有很多優點,它提供了多道編程,讓我們感覺我們每個人都擁有自己的CPU和其他資源,可以提高計算機的利用率。很多人就不理解了,既然進程這麽優秀,為什麽還要線程呢?其實,仔細觀察就會發現進程還是有很多缺陷的,主要體現在兩點上:

  • 進程只能在一個時間幹一件事,如果想同時幹兩件事或多件事,進程就無能為力了。

  • 進程在執行的過程中如果阻塞,例如等待輸入,整個進程就會掛起,即使進程中有些工作不依賴於輸入的數據,也將無法執行。

例如,我們在使用qq聊天, qq做為一個獨立進程如果同一時間只能幹一件事,那他如何實現在同一時刻 即能監聽鍵盤輸入、又能監聽其它人給你發的消息、同時還能把別人發的消息顯示在屏幕上呢?你會說,操作系統不是有分時麽?但我的親,分時是指在不同進程間的分時呀, 即操作系統處理一會你的qq任務,又切換到word文檔任務上了,每個cpu時間片分給你的qq程序時,你的qq還是只能同時幹一件事呀。

再直白一點, 一個操作系統就像是一個工廠,工廠裏面有很多個生產車間,不同的車間生產不同的產品,每個車間就相當於一個進程,且你的工廠又窮,供電不足,同一時間只能給一個車間供電,為了能讓所有車間都能同時生產,你的工廠的電工只能給不同的車間分時供電,但是輪到你的qq車間時,發現只有一個幹活的工人,結果生產效率極低,為了解決這個問題,應該怎麽辦呢?。。。。沒錯,你肯定想到了,就是多加幾個工人,讓幾個人工人並行工作,這每個工人,就是線程!

什麽是線程

線程是操作系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。一條線程指的是進程中一個單一順序的控制流,一個進程中可以並發多個線程,每條線程並行執行不同的任務

進程和線程的區別

(1)進程是資源的分配和調度的一個獨立單元,而線程是CPU調度的基本單元 (2)同一個進程中可以包括多個線程,並且線程共享整個進程的資源(寄存器、堆棧、上下文),一個進程至少包括一個線程。 (3)進程的創建調用fork或者vfork,而線程的創建調用pthread_create,進程結束後它擁有的所有線程都將銷毀,而線程的結束不會影響同個進程中的其他線程的結束 (4)線程是輕量級的進程,它的創建和銷毀所需要的時間比進程小很多,所有操作系統中的執行功能都是創建線程去完成的 (5)線程中執行時一般都要進行同步和互斥,因為他們共享同一進程的所有資源 (6)線程有自己的私有屬性TCB,線程id,寄存器、硬件上下文,而進程也有自己的私有屬性進程控制塊PCB,這些私有屬性是不被共享的,用來標示一個進程或一個線程的標誌 Python threading模塊 線程有2種調用方式,如下: 直接調用
import
threading import time def sayhi(num): # 定義每個線程要運行的函數 print("running on number:%s" % num) time.sleep(3) if __name__ == __main__: t1 = threading.Thread(target=sayhi, args=(1,)) # 生成一個線程實例 t2 = threading.Thread(target=sayhi, args=(2,)) # 生成另一個線程實例 t1.start() # 啟動線程 t2.start() # 啟動另一個線程 print(t1.getName()) # 獲取線程名 print(t2.getName())

繼承式調用

import threading
import time


class MyThread(threading.Thread):
    def __init__(self, num):
        threading.Thread.__init__(self)
        self.num = num

    def run(self):  # 定義每個線程要運行的函數

        print("running on number:%s" % self.num)

        time.sleep(3)


if __name__ == __main__:
    t1 = MyThread(1)
    t2 = MyThread(2)
    t1.start()
    t2.start()
    print(t1.getName())  # 獲取線程名
    print(t2.getName())

下面是一個對多線程的一個處理方法:(需要理解):

import threading
import time

def run(n):
    print("task: ",n)
    time.sleep(2)
    print("task done: ",n)

start_time = time.time()
for i in range(10):
    t = threading.Thread(target=run,args=(i,))
    t.start()

print("cost: ",time.time() - start_time)

運行結果如下所示:

是因為這個程序本身就是一個主線程,主線程又起了子線程,這時子線程和主線程已經沒關系了,相當於子線程和主線程是並行的。這就解釋了為什麽我的主線程啟動了子線程之後,沒有等子線程執行完畢,主線程就繼續往下走了。

但是現在有個問題,我們需要計算所有線程的執行時間,並且讓所有線程運行之後再運行主程序

這裏就需要用到線程裏的一個方法join()意思其實就是等待的意思代碼如下:

import threading
import time

def run(n):
    print("task: ",n)
    time.sleep(2)
    print("task done: ",n)

start_time = time.time()
t_obj = []    #存線程實例
for i in range(10):
    t = threading.Thread(target=run,args=(i,))
    t.start()
    t_obj.append(t)    #為了不阻塞後面線程的啟動,不在這裏join,先放到一個列表裏

for i in t_obj:    #循環線程實例列表,等待所有線程執行完畢
    i.join()

print("all thread is done")
print("cost: ",time.time() - start_time)

沒有加join的時候,主線程不會等子線程執行完畢再往下走,主線程和子線程的執行完全是並行的,沒有依賴關系,你執行,我也執行。但是,你會發現,最終退出的時候,主線程依然會等待所有的子線程執行完畢才退出程序。雖然不等你執行完畢才往下走,但是在程序退出之前,會默認還有一個join

但加了join的時候,主線程依賴子線程執行完畢之後, 再往下走,這是JOIN 的作用。

關於守護線程

如果將線程設置為守護線程,則主程序不會管線程是否執行完,只有主程序執行完畢之後,就會結束

代碼例子如下:

import threading
import time

def run(n):
    print("task: ",n)
    time.sleep(2)
    print("task done: ",n)

start_time = time.time()

for i in range(10):
    t = threading.Thread(target=run,args=(i,))
    t.setDaemon(True)    #把當前線程設置為守護線程
    t.start()

print("all thread is done",threading.current_thread(),threading.active_count())
print("cost: ",time.time() - start_time)

Python 基礎之-進程、線程