併發程式設計概述

2022-02-15 04:23:17 字數 3982 閱讀 6803

程序:程式執行的乙個過程

併發:是偽並行,即看起來是同時執行。單個cpu+多道技術就可以實現併發

並行:同時執行,只有具備多個cpu才能實現並行

單核下的多道技術:有四個核,六個任務,這樣同一時間有四個任務被執行,假設分別被分配給了cpu1,cpu2,cpu3,cpu4,一旦任務1遇到i/o就被迫中斷執行,此時任務5就拿到cpu1的時間片去執行,這就是單核下的多道技術。

multiprocessing模組:開啟子程序,並在子程序中執行我們定製的任務(比如函式)

process()

from multiprocessing import process

defpiao

(name):

print('%s piaoing' %name)

time.sleep(random.randrange(1,5))

print('%s piao end' %name)

if __name__ == '__main__':

#例項化得到四個物件

p1=process(target=piao,args=('egon',)) #必須加,號

p2=process(target=piao,args=('alex',))

p3=process(target=piao,args=('wupeqi',))

p4=process(target=piao,args=('yuanhao',))

#呼叫物件下的方法,開啟四個程序

p1.start()

p2.start()

p3.start()

p4.start()

print('主')

#由併發變成了序列,犧牲了執行效率,但避免了競爭

from multiprocessing import process,lock

import os,time

defwork

(lock):

lock.acquire() #加鎖

print('%s is running' %os.getpid())

time.sleep(2)

print('%s is done' %os.getpid())

lock.release() #釋放鎖

if __name__ == '__main__':

lock=lock()

for i in range(3):

p=process(target=work,args=(lock,))

p.start()

queue()---》佇列

守護程序

同乙個程序內的多個執行緒共享該程序內的位址資源

###### 建立執行緒的開銷要遠小於建立程序的開銷(建立乙個程序,就是建立乙個車間,涉及到申請空間,而且在該空間內建至少一條流水線,但建立執行緒,就只是在乙個車間內造一條流水線,無需申請空間,所以建立開銷小)

from threading import thread

import time

defsayhi

(name):

time.sleep(2)

print('%s say hello' %name)

if __name__ == '__main__':

t=thread(target=sayhi,args=('egon',))

t.start()

print('主線程')

多執行緒和多程序的區別:

執行緒的建立開銷極小;在主程序下開啟多個執行緒,每個執行緒都跟主程序的pid一樣;程序之間位址空間是隔離的;同一程序內開啟的多個執行緒是共享該程序位址空間的;

多執行緒用於io密集型,如socket,爬蟲,web

多程序用於計算密集型,如金融分析

守護執行緒和守護程序的區別:

gil並不是python的特性,它是在實現python解析器(cpython)時所引入的乙個概念。

gil本質就是一把互斥鎖,既然是互斥鎖,所有互斥鎖的本質都一樣,都是將併發執行變成序列,以此來控制同一時間內共享資料只能被乙個任務所修改,進而保證資料安全。

保護不同的資料的安全,就應該加不同的鎖。

100個執行緒去搶gil鎖,即搶執行許可權

肯定有乙個執行緒先搶到gil(暫且稱為執行緒1),然後開始執行,一旦執行就會拿到lock.acquire()

極有可能執行緒1還未執行完畢,就有另外乙個執行緒2搶到gil,然後開始執行,但執行緒2發現互斥鎖lock還未被執行緒1釋放,於是阻塞,被迫交出執行許可權,即釋放gil

直到執行緒1重新搶到gil,開始從上次暫停的位置繼續執行,直到正常釋放互斥鎖lock,然後其他的執行緒再重複2 3 4的過程

執行緒的乙個關鍵特性是每個執行緒都是獨立執行且狀態不可**。如果程式中的其 他執行緒需要通過判斷某個執行緒的狀態來確定自己下一步的操作,這時執行緒同步問題就會變得非常棘手。為了解決這些問題,我們需要使用threading庫中的event物件。

概述:例如程序池,就是用來存放程序的池子,本質還是基於多程序,只不過是對開啟程序的數目加上了限制。

程序池:

from concurrent.futures import threadpoolexecutor,processpoolexecutor

import os,time,random

deftask

(n):

print('%s is runing' %os.getpid())

time.sleep(random.randint(1,3))

return n**2

執行緒池:把processpoolexecutor換成threadpoolexecutor,其餘用法全部相同

是單執行緒下的併發,又稱微執行緒,纖程。英文名coroutine。一句話說明什麼是執行緒:協程是一種使用者態的輕量級執行緒,即協程是由使用者程式自己控制排程的。本質就是在單執行緒下,由使用者自己控制乙個任務遇到io阻塞了就切換另外乙個任務去執行,以此來提公升效率。

協程的切換開銷更小,屬於程式級別的切換,作業系統完全感知不到,因而更加輕量級

2. 單執行緒內就可以實現併發的效果,最大限度地利用cpu

協程的本質是單執行緒下,無法利用多核,可以是乙個程式開啟多個程序,每個程序內開啟多個執行緒,每個執行緒內開啟協程

2. 協程指的是單個執行緒,因而一旦協程出現阻塞,將會阻塞整個執行緒

必須在只有乙個單執行緒裡實現併發

修改共享資料不需加鎖

使用者程式裡自己儲存多個控制流的上下文棧

乙個協程遇到io操作自動切換到其它協程(如何實現檢測io,yield、greenlet都無法實現,就用到了gevent模組(select機制))

gevent 是乙個第三方庫,可以輕鬆通過gevent實現併發同步或非同步程式設計

單執行緒裡比如20個任務的**通常會既有計算操作又有阻塞操作,我們完全可以在執行任務1時遇到阻塞,就利用阻塞的時間去執行任務2。。。。如此,才能提高效率,就要用到gevent模組。

import gevent

defeat

(name):

print('%s eat 1' %name)

gevent.sleep(2)

print('%s eat 2' %name)

defplay

(name):

print('%s play 1' %name)

gevent.sleep(1)

print('%s play 2' %name)

g1=gevent.spawn(eat,'egon')

g2=gevent.spawn(play,name='egon')

g1.join()

g2.join()

#或者gevent.joinall([g1,g2])

print('主')

java 併發 高併發概述

為什麼需要並行 有關並行的重要概念 有關並行效能的2個重要定律 多執行緒基礎 執行緒的基本操作 守護執行緒 優先順序 中斷處理 基本的執行緒同步操作 各種同步控制工具的使用 併發容器及典型原始碼分析 同步工具 併發容器使用小案例 第5課 jdk並發包 執行緒池的基本使用 擴充套件和增強執行緒池 執行...

併發程式設計學習 併發程式設計的挑戰

死鎖 資源限制的挑戰 併發程式設計的目的是為了讓程式執行的更快,但是並不是啟動更多的執行緒,就能讓程式最大限度的併發執行。在進行併發程式設計時,如果希望通過多執行緒執行任務讓程式執行的更快,會面臨非常多的挑戰,比如上下文切換的問題,死鎖的問題,以及受限於硬體和軟體的資源限制問題 即使是單核處理器也支...

Kafka高併發原理概述

kafka是高吞吐低延遲的高併發 高效能的訊息中介軟體,在大資料領域有極為廣泛的運用。配置良好的kafka集群甚至可以做到每秒幾十萬 上百萬的超高併發寫入。那麼kafka到底是如何做到這麼高的吞吐量和效能的呢?這篇文章我們來一點一點說一下。首先kafka每次接收到資料都會往磁碟上去寫,如下圖所示。那...