【進程與線程】概念、threading、生產者消費者模型

程序並不能單獨運行,只有將程序裝載到內存中,系統爲它分配資源才能運行,而這種執行的程序就稱之爲進程python

程序和進程的區別:程序是指令的集合,它是進程運行的靜態描述文本;進程是程序的一次執行活動,屬於動態概念編程

進程的優勢:提供了多道編程,讓咱們感受咱們每一個人都擁有本身的CPU和其餘資源,能夠提升計算機的利用率。安全

進程的缺點多線程

  • 進程只能在一個時間幹一件事,若是想同時幹兩件事或多件事,進程就無能爲力了。
  • 進程在執行的過程當中若是阻塞,例如等待輸入,整個進程就會掛起,即便進程中有些工做不依賴於輸入的數據,也將沒法執行併發

 

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

 

io操做不佔用CPU,計算佔用CPU函數

python多線程不適合cpu密集操做型的任務,適合io操做密集型的任務ui

 

進程和線程的區別:spa

1.線程能夠共享建立它的進程的地址空間;操作系統

   進程有它們各自的地址空間。

2.線程能夠直接訪問其進程的數據段;

   進程有本身的父進程的數據段副本。

3.線程能夠直接與進程的其餘線程通訊;

   進程必須使用進程間通訊與同級進程通訊。

4.新線程很容易建立;

   新進程須要複製它的父進程。

5.線程能夠控制同一進程的線程;

   進程只能對子進程進行控制。

6.對主線程的更改(取消、優先級更改等)可能會影響該進程的其餘線程;

   對父進程的更改不會影響子進程。

 

GIL鎖(全局解釋器鎖Global Interpreter Lock)

在CPython中,全局解釋器鎖是防止多個本機線程同時執行Python字節碼的互斥體。主要是由於CPython的內存管理不是線程安全的。

GIL並非Python的特性,Python徹底能夠不依賴於GIL,可是GIL是CPython的特色。

 

python threading模塊:

import threading

def run1(n):
    print('threading',n)

if __name__ == '__main__':
    for i in range(50):
        t = threading.Thread(target=run1, args=(i,))#實例化一個線程
        t.start()    #啓動線程
        print(t.getName())    #獲取線程名

 Join & Daemon:

import threading,time

def runm1(n):
    print('threading',n)
    time.sleep(2)
    print('run thread done')

def main():
    for i in range(10):
        t = threading.Thread(target=run1, args=(i,))  # 實例化一個線程
        t.start()
        t.join(1)
        print('starting threading',t.getName())

if __name__ == '__main__':
    m = threading.Thread(target=main)#實例化一個線程
    m.setDaemon(True) #將main設置爲守護線程,當主線程結束時,主線程的守護線程就會當即結束
    m.start()    #啓動線程
    m.join(timeout=2) #等待線程執行結束
    print('main thread done')    #獲取線程名

 線程鎖(互斥鎖Mutex)

import threading,time

def run1():
    global n
    time.sleep(1)
    lock.acquire()#修改數據前加鎖
    n+=1
    lock.release()#修改後釋放

n=0
thread_list=[]
lock=threading.Lock() #生成全局鎖

if __name__ == '__main__':
    for i in range(100):
        t=threading.Thread(target=run1)
        t.start()
        thread_list.append(t)
    for t in thread_list:
        t.join()
        print('num:', n)

    print('final num:',n)

GIL和Lock:
GIL爲系統級的lock,Lock是用戶級的lock與GIL無關

RLock(遞歸鎖)

大鎖中包含子鎖時,防止lock的釋放混亂

import threading

def run1():
    print("grab the first part data")
    lock.acquire()
    global num
    num += 1
    lock.release()
    return num

def run2():
    print("grab the second part data")
    lock.acquire()
    global num2
    num2 += 1
    lock.release()
    return num2

def run3():
    lock.acquire()
    res = run1()
    print('--------between run1 and run2-----')
    res2 = run2()
    lock.release()
    print(res, res2)

if __name__ == '__main__':

    num, num2 = 0, 0
    lock = threading.RLock()
    for i in range(10):
        t = threading.Thread(target=run3)
        t.start()

while threading.active_count() != 1:
    print(threading.active_count())
else:
    print('----all threads done---')
    print(num, num2)

 Semaphore(信號量)

 互斥鎖同時只容許一個線程更改數據,而Semaphore是同時容許必定數量的線程更改數據,與互斥鎖用法相同。

import threading, time

def run(n):
    semaphore.acquire()
    time.sleep(1)
    print("run the thread: %s\n" % n)
    semaphore.release()

if __name__ == '__main__':
    num = 0
    semaphore = threading.BoundedSemaphore(5)  # 實例化semaphore鎖,最多容許5個線程同時運行
    for i in range(20):
        t = threading.Thread(target=run, args=(i,))
        t.start()

while threading.active_count() != 1:
    pass  # print threading.active_count()
else:
    print('----all threads done---')
    print(num)

 threading.Timer()

等待必定的時間調用函數

import threading

def hello(name):
    print('hello %s\n'%name)
    global timer
    timer = threading.Timer(2.0, hello, ["q1ang"])
    timer.start()

if __name__ == "__main__":
    timer = threading.Timer(2.0, hello, ["q1ang"])
    timer.start()

 Events

 經過Event來實現兩個或多個線程間的交互

import threading
import time

event=threading.Event()#實例化

def lighter():
    count=0
    event.set() #設置標誌位
    while True:
        if  count>20 and count<30:#改爲紅燈
            event.clear() #清除標誌位
            print('紅燈',count)
        elif count>30:
            event.set()    #設置標誌位
            count=0
        else:
            print('綠燈',count)
        time.sleep(1)
        count+=1
        print()

def car(name):
    while True:
        if event.is_set():#判斷標誌位啓動,(綠燈
            print('run')
            time.sleep(1)
        else:
            print('wait')
            event.wait() #等待設定標誌位
            print('start runing...')

light=threading.Thread(target=lighter,)
light.start()

c1=threading.Thread(target=car,args=('Tesla',))
c1.start()

queue隊列(解耦)線程queue

class queue.Queue(maxsize=0) #先入先出

class queue.LifoQueue(maxsize=0) #last in fisrt out 後入先出

class queue.PriorityQueue(maxsize=0) #存儲數據時可設置優先級的隊列

import queue

q=queue.Queue(maxsize=3)

q.put('d1')
q.put('d2')
q.put('d3')

print(q.qsize())

print(q.get(block=False,timeout=1))
print(q.get(block=False,timeout=1))
print(q.get(block=False,timeout=1))

 生產者消費者模型:解耦

生產者消費者模式是經過一個容器來解決生產者和消費者的強耦合問題。生產者和消費者彼此之間不直接通信,而經過阻塞隊列來進行通信,因此生產者生產完數據以後不用等待消費者處理,直接扔給阻塞隊列,消費者不找生產者要數據,而是直接從阻塞隊列裏取,阻塞隊列就至關於一個緩衝區,平衡了生產者和消費者的處理能力。

在併發編程中使用生產者和消費者模式可以解決絕大多數併發問題。該模式經過平衡生產線程和消費線程的工做能力來提升程序的總體處理數據的速度。

import threading,time
import queue

q=queue.Queue(maxsize=10)

def Producer():
    count=1
    while True:
        q.put('包子%s'%count)
        print('生產了包子%s'%count)
        time.sleep(0.5)
        count+=1

def Consumer(name):
    while True:
        print('[%s]取到[%s]並吃了它...'%(name,q.get()))
        time.sleep(2)

p=threading.Thread(target=Producer)
c1=threading.Thread(target=Consumer,args=('consumer1',))
c2=threading.Thread(target=Consumer,args=('consumer2',))

p.start()
c1.start()
c2.start()
相關文章
相關標籤/搜索