并發(fā)編程——多線程多進(jìn)程

一.并發(fā)編程

1.并發(fā)

并發(fā):同時接到多個任務(wù),同時執(zhí)行多個任務(wù),但是具體到某一時刻,只是在執(zhí)行某一個任務(wù),只是在短時間內(nèi)在多個任務(wù)之間進(jìn)行切換,模擬形成多個任務(wù)同時執(zhí)行的現(xiàn)象。

并發(fā)

2.并發(fā)編程

并發(fā)編程:在一臺處理器上同時執(zhí)行多個任務(wù),在某一時刻只執(zhí)行其中的一個任務(wù),相較于順序而言,并發(fā)極大的了提高執(zhí)行效率。

3.python對并發(fā)編程的支持

??????python長久以來一直支持不同方式的并發(fā)編程,包括線程、子進(jìn)程以及利用其他生成器的并發(fā)實(shí)現(xiàn), python在大部分系統(tǒng)上同時支持消息傳遞和基于線程的并發(fā)編程機(jī)制。python使用內(nèi)部全局解釋器鎖GIL來保證線程安全,GIL同時只允許一個線程執(zhí)行。

??????python提供了一些工具用于管理基于線程和進(jìn)程的并發(fā)操作,即使是簡單的程序也能夠使用這些工具使得任務(wù)并發(fā)進(jìn)行從而加快運(yùn)行速度。threading模塊為并發(fā)操作提供了一系列高級的、面向?qū)ο蟮腁PI。thread對象在一個進(jìn)程內(nèi)并發(fā)的運(yùn)行,分享內(nèi)存資源

python中的并發(fā)編程支持:
??????多線程并發(fā)機(jī)制——單進(jìn)程多線程:如果多個執(zhí)行單元需要頻繁訪問公共數(shù)據(jù)的時候【多線程并發(fā)】

??????多進(jìn)程并發(fā)機(jī)制——多進(jìn)程單線程:如果多個執(zhí)行單元執(zhí)行不同任務(wù)同時訪問不同的獨(dú)立數(shù)據(jù)【多進(jìn)程并發(fā)】

??????協(xié)程并發(fā)機(jī)制——單進(jìn)程單線程:并發(fā):通過程序代碼的方式,完成模擬CPU時間片并發(fā)任務(wù)的處理機(jī)制

二.進(jìn)程與線程

1. 線程與多線程編程

1.1什么是線程

??????線程:計算機(jī)程序運(yùn)行中的實(shí)際執(zhí)行者就是線程,線程又稱為輕量級進(jìn)程,是一個CPU的執(zhí)行單元,每個進(jìn)程至少會有一個主線程用于執(zhí)行程序

1.2多線程編程

??????操作方式:python本身支持多任務(wù)處理,并提供了三種操作方式:
???????????? ?????? ??????1)多線程任務(wù)處理機(jī)制
?????? ?????? ?????? ??????2)多進(jìn)程任務(wù)處理機(jī)制
?????? ?????? ?????? ??????3)協(xié)程多任務(wù)處理機(jī)制
?????? ?????? ?????? ??????python官方推薦的_threading模塊的多線程并發(fā)機(jī)制編程主要有兩種操作方式:
?????? ?????? ?????? ??????1)函數(shù)式的線程創(chuàng)建方式,適合面向過程中的并發(fā)編程的實(shí)現(xiàn)
?????? ?????? ?????? ??????2)面向?qū)ο笫骄幊蹋m合面向程序的并發(fā)編程的實(shí)現(xiàn)

??????多線程:通過threading模塊中的Thread函數(shù),可以實(shí)現(xiàn)多線程程序的運(yùn)行。單線程實(shí)現(xiàn)模式就是在同一時間有且只有一個線程正在執(zhí)行,多線程實(shí)現(xiàn)模式是在同一時間可以有多個線程同時執(zhí)行,因此在效率上多線程要遠(yuǎn)遠(yuǎn)高于單線程。

??????線程狀態(tài):線程擁有兩種狀態(tài),分別為join和daemon。Join狀態(tài)是獨(dú)占模式,獨(dú)占CPU的運(yùn)行單元,只有在此線程完成或超時后才能繼續(xù)運(yùn)行其他的線程。Daemon屬性是用于標(biāo)識某個線程是否守護(hù)線程。守護(hù)線程是跟主線程緊密相連的,即當(dāng)主線程退出時,無論守護(hù)線程是否執(zhí)行完成,都會隨主線程一起退出。

??????線程鎖:在多個線程同時執(zhí)行時,可能會由于訪問的是同一種數(shù)據(jù)而造成線程之間的沖突,一旦線程之間沖突,就會造成一些錯誤的出現(xiàn)。為了避免這種不必要的現(xiàn)象的出現(xiàn),鎖的存在就很有必要了,在多個線程同時訪問某一數(shù)據(jù)時,給當(dāng)前某一線程正在訪問的數(shù)據(jù)上鎖,使得其他進(jìn)程無法訪問,避免數(shù)據(jù)沖突的發(fā)生,當(dāng)線程執(zhí)行結(jié)束后再給這一段數(shù)據(jù)解鎖,下一進(jìn)程才可繼續(xù)訪問。雖然線程鎖能夠幫助我們避免數(shù)據(jù)沖突的問題,但凡事都有利有弊,如果在上鎖的過程中沒有一個良好的認(rèn)知的話,會使得這個鎖成為死鎖,致使數(shù)據(jù)重復(fù)上鎖從而無限循環(huán)執(zhí)行無法進(jìn)入下一步的訪問。

??????線程事件:事件Event用于多個線程之間的互相通信,它可以被多個線程訪問,可以標(biāo)記不同的狀態(tài),并且能用于控制線程等待運(yùn)行之間的轉(zhuǎn)換。在線程執(zhí)行時,使用event.wait()使線程進(jìn)入等待狀態(tài),通過event.set()標(biāo)記某一線程,標(biāo)記之后繼續(xù)執(zhí)行,同時,在轉(zhuǎn)換的過程中,需要合理運(yùn)用event.clear()清除標(biāo)記防止線程執(zhí)行順序的錯亂

??????線程條件:多個線程互相通信時,可能會根據(jù)實(shí)際情況進(jìn)行線程之間的等待與執(zhí)行的切換,在python中,通過condition()進(jìn)行條件的判斷,只有當(dāng)滿足條件時,事件才會在等待與執(zhí)行中進(jìn)行轉(zhuǎn)換

??????線程隊列:線程之間共享數(shù)據(jù)的訪問問題和線程之間的通信是線程管理中的主要問題。為了更好的解決這一問題。Python提供了一個數(shù)據(jù)類型,隊列Queue(),隊列主要用于多線程并發(fā)模式下,安全的訪問數(shù)據(jù)且不會造成數(shù)據(jù)之間的沖突,通過向隊里中添加數(shù)據(jù)和獲取數(shù)據(jù)達(dá)到線程和諧執(zhí)行的目的。

??????面向?qū)ο蠖嗑€程:面向?qū)ο蟮亩嗑€程,通過重寫Thread類型的run()方法,創(chuàng)建自定義線程的對象后,調(diào)用start()方法啟動

2.進(jìn)程與多進(jìn)程編程

2.1什么是進(jìn)程

??????進(jìn)程:通俗的來說,一個進(jìn)程計算機(jī)上正在運(yùn)行的一個程序,是計算機(jī)中一個程序在一個數(shù)據(jù)集上一次動態(tài)的執(zhí)行過程,主要包含三部分內(nèi)容:
?????? ?????? ??????1)程序:描述進(jìn)程的功能以及處理流程
?????? ?????? ??????2)數(shù)據(jù)集:功能處理過程中需要的資源數(shù)據(jù)
?????? ?????? ??????3)進(jìn)程控制:嚴(yán)格控制進(jìn)程執(zhí)行過程中的各種狀態(tài)

2.2多進(jìn)程編程

??????進(jìn)程:進(jìn)程是正在執(zhí)行的應(yīng)用程序,一個進(jìn)程包含了應(yīng)用程序的所有信息,一個應(yīng)用程序通過其功能的多樣性,可以通過多個進(jìn)程并發(fā)來實(shí)現(xiàn)。 多進(jìn)程的面向?qū)ο髮?shí)現(xiàn):多進(jìn)程的面向?qū)ο髮?shí)現(xiàn)類似于多線程,自定義類型進(jìn)程,通過繼承系統(tǒng)標(biāo)準(zhǔn)類型multiprocessing Process ,重寫父類的run()方法,在方法中定義執(zhí)行代碼,使用創(chuàng)建的自定義類型進(jìn)程的獨(dú)象,調(diào)用對象的start()方法啟動一個新的進(jìn)程

??????帶參數(shù)的多進(jìn)程:在多進(jìn)程的操作模式下,全局變量是共享的,在方便操作的同時,也為數(shù)據(jù)的修改帶來諸多不便。此時,我們可以通過兩種方法進(jìn)行觀察多進(jìn)程模式下的數(shù)據(jù)處理。其一為全局變量的數(shù)據(jù),在多個進(jìn)程執(zhí)行的過程中,每個進(jìn)程本身都相當(dāng)于是一個相互獨(dú)立運(yùn)行的程序,每個進(jìn)程中全局?jǐn)?shù)據(jù)的變量都是相互獨(dú)立的;其二為參數(shù)傳遞,給多進(jìn)程并發(fā)處理函數(shù)傳遞參數(shù),并不能使數(shù)據(jù)被多個進(jìn)程共享,函數(shù)執(zhí)行并發(fā)操作時,每一個進(jìn)程都會獨(dú)自拷貝一份全局變量進(jìn)行使用,從而使多個進(jìn)程使用的同一個全局變量不互相影響

??????內(nèi)置進(jìn)化池:內(nèi)置進(jìn)化池是多線程的簡化,是面向過程多進(jìn)程的操作優(yōu)化方式。有了進(jìn)程池后,可以簡單的模擬多任務(wù)并行的操作,使多個任務(wù)被幾個進(jìn)程平均分配進(jìn)行處理

??????多個進(jìn)程通信:不同線程之間的數(shù)據(jù)通信,涉及到核心的數(shù)據(jù)共享問題,主要由multiprocessing manager類型實(shí)現(xiàn),該類型內(nèi)置了大量的用于數(shù)據(jù)共享的操作。多個進(jìn)程之間的通信操作,數(shù)據(jù)的傳遞由multiprocessing模塊中的隊列queue實(shí)現(xiàn),同時,此模塊中的pipe可以更加有好的進(jìn)行多個進(jìn)程之間的通信

2.3.進(jìn)程與線程的對比

??????對比如下:
?????? ?????? ??????1)一個進(jìn)程可以有多個線程,但至少有一個主線程
?????? ?????? ??????2)一個線程只能屬于一個進(jìn)程
?????? ?????? ??????3)一個進(jìn)程中多個線程,可以共享進(jìn)程中提供的數(shù)據(jù)
?????? ?????? ??????4)CPU運(yùn)算分配給線程,CPU執(zhí)行運(yùn)算的是線程
?????? ?????? ??????5)線程是最小的運(yùn)行單元,進(jìn)程是最小的資源管理單元

三.python中的模塊

1.模塊的作用

模塊:

1)在一個python模塊中可以包含的數(shù)據(jù)有變量、函數(shù)和類型等,是一個完整獨(dú)立的代碼塊

2)獨(dú)立模塊中的變量分為全局變量和局部變量,全局變量是整個模塊的變量,可以被其他模塊引入使用;局部變量是當(dāng)前模塊中某個函數(shù)或類型的變量,只能被當(dāng)前的函數(shù)及類型使用

3)模塊被其他模塊引入后,相當(dāng)于在當(dāng)前模塊重寫了被引入模塊的代碼,所以會執(zhí)行被引入模塊中的所有代碼

4)模塊中的測試代碼可以包含在if name == “main”: 這樣的語句中,在這些語句中的模塊不會在引入其他模塊時執(zhí)行

5)一個標(biāo)準(zhǔn)模塊的定義方式分為以下幾個步驟

●#coding:utf-8)

● 引入系統(tǒng)標(biāo)準(zhǔn)模塊

● 引入第三方模塊

●引入自定義模塊

● 聲明定義變量

●聲明定義函數(shù)

●聲明定義類型

● 當(dāng)前模塊測試代碼
模塊的作用:
1)一個.py文件就是一個模塊,模塊有利于函數(shù)的維護(hù),方便函數(shù)的調(diào)用

2)避免函數(shù)名和變量名沖突,每個模塊獨(dú)立的命名空間

3)可以定義函數(shù)、類和變量,模塊里也能包含可執(zhí)行的代碼

2.模塊中常見的類型/方法/函數(shù)

TODO

3._thread模塊

thread類型屬性和方法:

名稱 描述
init(group,target,name,args,kwargs) 構(gòu)造方法、創(chuàng)建線程類型
is_alive()/isAlive() 判斷當(dāng)前線程是否 alive 狀態(tài)
run() 線程執(zhí)行方法,自定義線程必須重寫該函數(shù)
start() 線程啟動方法
join([timeout=None]) 線程獨(dú)占,等待當(dāng)前線程運(yùn)行結(jié)束或者超時
ident 標(biāo)識當(dāng)前線程的唯一編號
name 當(dāng)前線程名稱
daemon 布爾值,判斷當(dāng)前線程是否守護(hù)線程

注意事項(xiàng)

同一個對象不能被多個線程操作*
* 線程的操作主體都是Thread對象(或者是它的子類)由這個對象執(zhí)行start方法* 
區(qū)別在于 
- 繼承Thread類之后,直接就用這個子類去執(zhí)行start方法 
- 實(shí)現(xiàn)Runnable接口的話,是將這個類作為參數(shù)傳入到Thread的構(gòu)造方法里面,再由Thread來執(zhí)行start方法。
所以說,線程操作的主體都是Thread對象或者是它的子類對象。

簡單實(shí)現(xiàn)

# -*- coding: utf-8 -*-
# 引入依賴的模塊

import _thread,time

# 定義處理函數(shù)

def sing():
    for i in range(10):
        print("唱歌。。。。。。。。。。。。")

def dance():
    for j in range(10):
        print("跳舞........................")

# 單線程
_thread.start_new_thread(sing,())
_thread.start_new_thread(dance,())

time.sleep(1)

4.threading模塊

threading實(shí)現(xiàn)的面向函數(shù)的多線程:
●多線程購票程序[多個窗口同時售票]

# -*- coding: utf-8 -*-
#引入模塊
import threading,time
ticket_count = 10
lock = threading.Lock()

def sale_ticket():
    # 導(dǎo)入全局變量
    global ticket_count
    time.sleep(0.5)
    while True:
        time.sleep(0.5)
        # 上鎖
        if lock.acquire():
            if ticket_count > 0:
                ticket_count -= 1
                print(threading.current_thread().getName(),"售票1張,剩余票數(shù):",ticket_count)

            else:
                # print( "窗口票已售空" + str(i))
                # threading.Thread(name="窗口" + str(i)+ '票已售空', target=sale_ticket)
                print(threading.current_thread().getName(), "票已售完")
                # 釋放鎖
                lock.release()
                break
            lock.release()


if __name__ == "__main__":
    for i in range(1,7):
        t = threading.Thread(name= "窗口"+str(i),target=sale_ticket)
        t.start()

●多線程-線程通信-事件[Event]-買早餐[核心:兩個線程之間的數(shù)據(jù)依賴]

# -*- coding: utf-8 -*-
import threading,time

event = threading.Event()

def xf():
    print("小販 :炸油條")
    time.sleep(0.5)
    print("小販 :賣油條")
    time.sleep(1)
    event.set()
    event.clear()
    event.wait()
    print("小販 :找錢")

    time.sleep(1)
    event.wait()
    print("小販 :謝謝惠顧")

def gk():
    time.sleep(1)
    print("顧客 :買油條")
    time.sleep(1)
    print("顧客 :吃油條")
    time.sleep(1)
    print("顧客 :吃飽了")
    time.sleep(1)
    event.set()
    event.clear()
    print("顧客 :付錢")
    time.sleep(1)
    event.set()
    print("顧客 :我走了")


if __name__ == "__main__":
    x = threading.Thread(target=xf)
    g = threading.Thread(target=gk)
    x.start()
    g.start()

●多線程-線程通信-條件[Condition]-生產(chǎn)者消費(fèi)者


# -*- coding: utf-8 -*-
import threading,time,random

con = threading.Condition()

basket = list()

def food():
    while True:
        con.acquire()
        if len(basket) >= 10:
            print(threading.current_thread().getName(),"菜已上滿,請慢用")
            time.sleep(1)
            con.wait()

        else:
            cai = random.randint(0,5)
            print(threading.current_thread().getName(),"上菜",cai)
            time.sleep(1)
            basket.append(cai)
            con.notify()

        con.release()

def chi():
    while True:
        con.acquire()
        if len(basket) <= 0:
            print(threading.current_thread().getName(),"沒菜了")
            time.sleep(1)
            con.wait()


        else:
            cai = basket.pop()
            print(threading.current_thread().getName(),"吃了",cai)
            time.sleep(1)
            con.notify()

        con.release()


if __name__  == "__main__":
    for i in range(2):
        a = threading.Thread(name="生產(chǎn)者" + str(i) +"號",target=food)
        a.start()

    for i in range(3):
        b = threading.Thread(name="消費(fèi)者" + str(i) + "號",target=chi)
        b.start()

●多線程-數(shù)據(jù)容器-隊列[Queue]-生產(chǎn)者消費(fèi)者

# -*- coding: utf-8 -*-
import threading,time,random,queue
basket = queue.Queue(5)

def sc():
    while True:
        time.sleep(1)
        n = random.randint(0,5)
        try:
            basket.put(n,timeout=1)
            print("生產(chǎn)+1",n)
        except:
            print("藍(lán)已滿")

def xf():
    while True:
        time.sleep(1)
        try:
            n = basket.get(timeout=1)
            print("消費(fèi)+1",n)
        except:
            print("藍(lán)已空")


if __name__ =="__main__":
    for i in range(2):
        a = threading.Thread(target=sc)
        a.start()

    for j in range(1):
        b = threading.Thread(target=xf)
        b.start()
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 必備的理論基礎(chǔ) 1.操作系統(tǒng)作用: 隱藏丑陋復(fù)雜的硬件接口,提供良好的抽象接口。 管理調(diào)度進(jìn)程,并將多個進(jìn)程對硬件...
    drfung閱讀 3,769評論 0 5
  • 一. 操作系統(tǒng)概念 操作系統(tǒng)位于底層硬件與應(yīng)用軟件之間的一層.工作方式: 向下管理硬件,向上提供接口.操作系統(tǒng)進(jìn)行...
    月亮是我踢彎得閱讀 6,173評論 3 28
  • 本文是我自己在秋招復(fù)習(xí)時的讀書筆記,整理的知識點(diǎn),也是為了防止忘記,尊重勞動成果,轉(zhuǎn)載注明出處哦!如果你也喜歡,那...
    波波波先森閱讀 11,629評論 4 56
  • 一切源于2016年。 我初三那年,我爸媽離婚了。 我難以描述當(dāng)時的心情,我只記得,爸媽藏起來的離婚協(xié)議,我自己發(fā)現(xiàn)...
    5月七閱讀 354評論 0 0
  • 如愿考上大學(xué)的我,卻沒有如愿過上自己想要的生活。 猶記得高考完那年漫長的暑假,天氣很熱,蟬鳴很脆,樹葉很綠…喜歡天...
    范特西VVV西西西QAQ閱讀 276評論 0 0

友情鏈接更多精彩內(nèi)容