Python學習手冊 (五)----線程/進程 函數

Python學習手冊:


1.python語法:列表推導式

2.numpy 一些函數

3.matplotlib 一些函數

4.matplotlib 高階函數

5.線程/進程 函數


1.進程和線程是什麼:

1.1什麼是線程:

線程(Thread)也叫輕量級進程,是操作系統能夠進行運算調度的最小單位,它被包涵在進程之中,是進程中的實際運作單位。線程自己不擁有系統資源,只擁有一點兒在運行中必不可少的資源,但它可與同屬一個進程的其它線程共享進程所擁有的全部資源。

1.2python的函數:

python主要是通過thread和threading這兩個模塊來實現多線程支持。python的thread模塊是比較底層的模塊,python的threading模塊是對thread做了一些封裝,可以更加方便的被使用。但是python(cpython)由於GIL的存在無法使用threading充分利用CPU資源,如果想充分發揮多核CPU的計算能力需要使用multiprocessing模塊(Windows下使用會有諸多問題)。

1.3舉個簡單的進程線程概念例子:

假定有一 7 * 24 小時不停工的工廠,由於其電力有限,一次僅供一個車間使用,當一個車間在生產時,其他車間停工。在這裏我們可以理解這個工廠相當於操作系統,供電設備相當於 CPU,一個車間相當於一個進程。
一個車間裏,可以有很多工人。他們協同完成一個任務。車間的空間是工人們共享的,這裏一個工人就相當於一個線程,一個進程可以包括多個線程。比如許多房間是每個工人都可以進出的。這象徵一個進程的內存空間是共享的,每個線程都可以使用這些共享內存。
有時候資源有限,比如有些房間最多隻能容納一個人,當一個人佔用的時候,其他人就不能進去,只能等待。這代表一個線程使用某些共享內存時,其他線程必須等它結束,才能使用這一塊內存。
一個防止他人進入的簡單方法,就是門口加一把鎖。先到的人鎖上門,後到的人看到上鎖,就在門口排隊,等鎖打開再進去。這就叫”互斥鎖”(Mutual exclusion,縮寫 Mutex ),防止多個線程同時讀寫某一塊內存區域。
還有些房間,可以同時容納 n 個人,比如廚房。也就是說,如果人數大於 n,多出來的人只能在外面等着。這好比某些內存區域,只能供給固定數目的線程使用。這時的解決方法,就是在門口掛 n 把鑰匙。進去的人就取一把鑰匙,出來時再把鑰匙掛回原處。後到的人發現鑰匙架空了,就知道必須在門口排隊等着了。這種做法叫做”信號量”( Semaphore ),用來保證多個線程不會互相沖突。

線程有 就緒、阻塞、運行 三種基本狀態。

  1. 就緒狀態是指線程具備運行的所有條件,邏輯上可以運行,在等待處理機;
  2. 運行狀態是指線程佔有處理機正在運行;
  3. 阻塞狀態是指線程在等待一個事件(如某個信號量),邏輯上不可執行。

2.全局解釋器鎖(GIL)

全局解釋器鎖(Global Interpreter Lock,GIL)是一個加在解釋器上的鎖,即使多個線程直接不會相互影響在同一個進程下也只有一個線程使用CPU
在同一個進程中只要有一個線程獲取了全局解釋器(CPU)的使用權限,那麼其他的線程就必須等待該線程的全局解釋器(CPU)使用權消失後才能使用全局解釋器(CPU)

3.多線程的threading Event()

event它是溝通中最簡單的一個過程之中,一個線程產生一個信號。Python 通過threading.Event()產生一個event對象。event對象維護一個內部標誌(標誌初始值爲False),通過set()將其置爲True。wait(timeout)則用於堵塞線程直至Flag被set(或者超時,可選的),isSet()用於查詢標誌位是否爲True,Clear()則用於清除標誌位(使之爲False)。

3.1 設置\清除信號

Event的set()方法可設置Event對象內部的信號標誌爲真,Event對象提供了isSet()方法來推斷其內部信號標誌的狀態,使用set()方法後,isSet()方法返回True。clear()方法可清除Event對象內部的信號標誌(設爲False)。使用clear方法後。isSet()方法返回False

3.2 等待

當Event對象的內部信號標誌爲False時。wait方法一直堵塞線程等待到其爲真或者超時(若提供,浮點數,單位爲秒)才返回,若Event對象內部標誌爲True則wait()方法馬上返回。

4.Daemon線程(守護線程)

當且僅當主線程運行時有效,當其他非Daemon線程結束時可自動殺死所有子線程

Daemon線程。

1. 如果某個子線程的daemon屬性爲True(守護線程),
主線程運行結束時不對這個子線程進行檢查而直接退出,同時所有daemon值爲True的子線程將隨主線程一起結束,而不論是否運行完成。
2. 如果某個子線程的daemon屬性爲False(用戶線程),
主線程結束時會檢測該子線程是否結束,如果該子線程還在運行,則主線程會等待它完成後再退出;

5.python中的同步線程隊列

5.1Queue的種類:

Python的queue模塊中提供了同步的、線程安全的隊列類,包括FIFO(先入先出)隊列Queue,LIFO(後入先出)隊列LifoQueue,和優先級隊列PriorityQueue。這些隊列都實現了鎖原語,能夠在多線程中直接使用。可以使用隊列來實現線程間的同步。

5.2基本方法:

  • Queue.Queue(maxsize=0) FIFO, 如果maxsize小於1就表示隊列長度無限
  • Queue.LifoQueue(maxsize=0) LIFO, 如果maxsize小於1就表示隊列長度無限
  • Queue.qsize() 返回隊列的大小
  • Queue.empty() 如果隊列爲空,返回True,反之False
  • Queue.full() 如果隊列滿了,返回True,反之False
  • Queue.get([block[, timeout]]) 讀隊列,timeout等待時間
  • Queue.put(item, [block[, timeout]]) 寫隊列,timeout等待時間
  • Queue.queue.clear() 清空隊列

6.thread.join():

(用戶進程)所完成的工作就是線程同步,即主線程任務結束之後,進入阻塞狀態,一直等待其他的子線程執行結束之後,主線程在終止

  • join有一個timeout參數:
    **當設置守護線程時,含義是主線程對於子線程等待timeout的時間將會殺死該子線程,最後退出程序。**所以說,如果有10個子線程,全部的等待時間就是每個timeout的累加和。簡單的來說,就是給每個子線程一個timeout的時間,讓他去執行,時間一到,不管任務有沒有完成,直接殺死。
    沒有設置守護線程時,主線程將會等待timeout的累加和這樣的一段時間,時間一到,主線程結束,但是並沒有殺死子線程,子線程依然可以繼續執行,直到子線程全部結束,程序退出。

3.4樣例代碼

#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
import Queue
import threading
import time
 
exitFlag = 0
 
class myThread (threading.Thread):
    def __init__(self, threadID, name, q):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.q = q
    def run(self):
        print "Starting " + self.name
        process_data(self.name, self.q)
        print "Exiting " + self.name
 
def process_data(threadName, q):
    while not exitFlag:
        queueLock.acquire()
        if not workQueue.empty():
            data = q.get()
            queueLock.release()
            print "%s processing %s" % (threadName, data)
        else:
            queueLock.release()
        time.sleep(1)
 
threadList = ["Thread-1", "Thread-2", "Thread-3"]
nameList = ["One", "Two", "Three", "Four", "Five"]
queueLock = threading.Lock()
workQueue = Queue.Queue(10)
threads = []
threadID = 1
 
# 創建新線程
for tName in threadList:
    thread = myThread(threadID, tName, workQueue)
    thread.start()
    threads.append(thread)
    threadID += 1
 
# 填充隊列
queueLock.acquire()
for word in nameList:
    workQueue.put(word)
queueLock.release()
 
# 等待隊列清空
while not workQueue.empty():
    pass
 
# 通知線程是時候退出
exitFlag = 1
 
# 等待所有線程完成
for t in threads:
    t.join()
print "Exiting Main Thread"

參考博文:https://blog.csdn.net/somezz/article/details/80963760

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章