多線程多進(jìn)程以及python中的實(shí)現(xiàn)

多線程和多進(jìn)程

通常在硬件層面上和操作系統(tǒng)層面上都存在線程的概念。但是這兩個(gè)概念是完全不同的,是一個(gè)詞匯在不同層面上的不同意思。

CPU數(shù),核心數(shù),硬件的線程數(shù)

  • CPU數(shù)指的是一個(gè)計(jì)算機(jī)主板上實(shí)際上卡槽中插入的CPU個(gè)數(shù),由卡槽socket決定。一般的計(jì)算機(jī)是一個(gè)卡槽,因?yàn)槎鄠€(gè)卡槽的CPU之間共享內(nèi)存等資源需要高級(jí)的技術(shù)。一般服務(wù)器是多個(gè)物理CPU的,也就是CUP數(shù)對(duì)于個(gè)人計(jì)算機(jī)是1,對(duì)于服務(wù)器是>1.

  • 核心數(shù)指的是單個(gè)CPU的內(nèi)部存在的可以同時(shí)處理的處理器。

    • 這里首先強(qiáng)調(diào)是這里的核心是CPU內(nèi)部存在一定的硬件支持的
    • 第二是這里的同時(shí)指的是真正的同時(shí)處理,不同于操作系統(tǒng)層面上的同時(shí)可以是單個(gè)核心不斷切換導(dǎo)致的同時(shí)。
  • 線程數(shù)thread,邏輯處理器logical processor,或者虛擬核心virtual core,是同一個(gè)東西,指的是一個(gè)核心中可以存在著SMT(simultaneous multithreading)或者HT(hyper-threading)技術(shù),這些技術(shù)可以使得單個(gè)核心同時(shí)執(zhí)行多個(gè)線程,就相當(dāng)于上文提到的單個(gè)核心數(shù)內(nèi)部又存在多個(gè)子核心,總的核心是這些子核心數(shù)之和。

所以系統(tǒng)總的核心數(shù)實(shí)際上是上面所有的乘積。也就是邏輯處理器數(shù)量= CPU數(shù)* 核心數(shù) * 超線程數(shù)(SMT or HT) 。

最后在硬件層面上其實(shí)線程和進(jìn)程是一樣的,指的就是幾個(gè)核心或者存在超線程時(shí)候的總的線程數(shù)。

Linux查看以上信息的命令,lscpu或者到/proc/cpuinfo查看。

Windows可以直接看任務(wù)管理器。

操作系統(tǒng)層面的進(jìn)程和線程

  1. 操作系統(tǒng)層面上(不嚴(yán)格講)
  • 一個(gè)線程指的是一串又有邏輯的指令,要先執(zhí)行a,在執(zhí)行b,等等。
  • 一個(gè)進(jìn)程簡單理解就指的是一個(gè)程序,或者應(yīng)用程序。
  1. 舉例來說,打開一個(gè)應(yīng)用程序,比如word,就會(huì)啟動(dòng)一個(gè)或者多個(gè)進(jìn)程,每個(gè)進(jìn)程執(zhí)行一個(gè)任務(wù),同時(shí)為了執(zhí)行一個(gè)任務(wù)可能需要多個(gè)子任務(wù),這些子任務(wù)就是線程。比如寫入word時(shí)候需要自動(dòng)保存也需要拼寫檢查,這就是同一個(gè)進(jìn)程下的不同的線程。

  2. 操作系統(tǒng)層面的多進(jìn)程和多線程指的是,基于單核沒有超線程的CPU來說,操作系統(tǒng)會(huì)調(diào)度這些進(jìn)程或者線程進(jìn)行極短時(shí)間內(nèi)的切換,以至于我們看不出來是切換的。所以任務(wù)是同時(shí)的。所以單核當(dāng)CPU沒辦法實(shí)現(xiàn)真正的并行,單次或者每個(gè)時(shí)間只能進(jìn)行一個(gè)線程或者進(jìn)程,但是只要我切換的夠快,時(shí)間就追不上我。還需要注意,一般我們使用程序數(shù)量遠(yuǎn)遠(yuǎn)多于計(jì)算機(jī)總的邏輯處理器數(shù)量,所以即便對(duì)于多核CPU來說,系統(tǒng)的切換也是極其重要的。

  3. 進(jìn)程和線程本質(zhì)是一個(gè)包含的關(guān)系,所以多進(jìn)程和多線程機(jī)制是不同的,比如同一個(gè)進(jìn)程內(nèi)的多線程可以共享內(nèi)存等等資源,通信也更加簡單,每個(gè)線程需要自己的堆棧寄存器,所以占用資源少,多進(jìn)程就是相對(duì)獨(dú)立的,需要更多的內(nèi)存等。所以分為多線程,多進(jìn)程,和多線程多進(jìn)程三種。多線程是指在一個(gè)進(jìn)程中存在多個(gè)線程。

python的多進(jìn)程(多線程)

python數(shù)值計(jì)算應(yīng)該使用多進(jìn)程的,對(duì)于計(jì)算密集型的,這樣比較穩(wěn)定穩(wěn)定可靠,另外多線程對(duì)于有些變量會(huì)交錯(cuò)使用,導(dǎo)致結(jié)果容易錯(cuò)誤。I/O密集型的大部分都在等待寫入到硬盤時(shí)間, 對(duì)于I/O密集型的可以用多線程。另外python還有GIL。

多進(jìn)程

  • 利用multiprocessing中的Process實(shí)例,方法

    from multiprocessing import Process
    
    p=Process(target=func,args=(arg,))#要進(jìn)行多進(jìn)程的程序需要寫入到一個(gè)函數(shù)中。
    p.start()
    p.join()#等待進(jìn)程都結(jié)束,用于同步。
    
    
  • 利用multiprocessing 中的Pool實(shí)現(xiàn),啟動(dòng)大量的進(jìn)程。

    from multiprocessing import Pool
    
    p=Pool(4)#需要的logical 核心數(shù)量,一般和計(jì)算機(jī)有關(guān)。
    
    def func():
        pass
    
    for ii in range(5)
        p.apply_async(target=func,args=(arg,))
        p.close()#在close之后就不能加入新的進(jìn)程。
        p.join()#用于等待所有進(jìn)程結(jié)束,必須在close之后。
    
  • 子進(jìn)程之間的通信,利用queue.可以實(shí)現(xiàn)不同的進(jìn)程寫或者讀取同一個(gè)結(jié)果。

    from multiprocessing import Process, Queue
    import time
    
    def wirte(a):
        valus=['A','B','C']
        for ii in valus:
            a.put(ii)
            time.sleep(5)
    
    def read(a):
        while True:
            q.get(True)
    
    q=Queue()
    pw=processing(target=,args=(q,))
    pr=processing(target=,args=(q,))
    pw.start()
    pr.start()
    pw.join()
    pr.join() or pr.terminate()#手動(dòng)終止程序。
    
  • 多進(jìn)程的返回值

    返回值初級(jí)用法

    • join的作用是主程序等待這個(gè)程序結(jié)束繼續(xù)執(zhí)行p.join以后的內(nèi)容,如果沒有join則執(zhí)行完程序不再執(zhí)行以后的內(nèi)容。
    • 這里使用結(jié)束并行之后使用get或者多進(jìn)程的返回值。

多線程

  • 利用threading,方法和multiprocessing類似

    import threading
    
    p=threading.Thread(target=,name='loop')
    p.start()
    p.join()
    threading.current_thread().name用于返回當(dāng)前線程名字。
    
  • 啟動(dòng)一個(gè)進(jìn)程內(nèi)的多線程時(shí)候, 都會(huì)首先建立一個(gè)主線程名字是Mainthread,接著會(huì)建立其他的子線程,名字默認(rèn)是thread-1,Thead-2,或者是我們可以給定一個(gè)名字,比如上面所示,我們給定了一個(gè)loop的名字name.

  • 該模塊中又一個(gè)current_thread()的實(shí)例,用于返回當(dāng)前線程。

  • 多線程會(huì)有時(shí)候出錯(cuò),例如。

一般來說用計(jì)算過程中多進(jìn)程就夠了。

python中qutip的并行

  • 并行使用 qutip.parapallel.parfor,和 parallel.parallel_map,這兩種函數(shù)進(jìn)行并行。本質(zhì)上qutip中的并行是借用了multiprocessing, 而且mcsolve方法中多條軌跡也是并行的,所以不能嵌套并行和mcsolve。

  • 使用方法:首先定義一個(gè)函數(shù)該函數(shù)是要進(jìn)行并行的函數(shù),之后使用parfor傳入函數(shù)和參數(shù)進(jìn)行并行。

    def func(x):
        return x**2
    
    parfor(func,range(10))
    ##
    parallwl_map(func,range(10))
    
  • 這兩個(gè)函數(shù)略有區(qū)別,返回的結(jié)果的順序是不同的。(具體參考文檔P127)

  • 該函數(shù)可以輸入的變量不限于數(shù)字。

  • 該函數(shù)可以傳入多個(gè)參數(shù),這些參數(shù)的遍歷方法不同,對(duì)于parfor和parallel有不同的遍歷參數(shù)方法,同時(shí)支持傳入任意關(guān)鍵詞參數(shù),但是不會(huì)用于計(jì)算。進(jìn)行計(jì)算的僅僅是函數(shù)要求的那些。此外parfor的關(guān)鍵詞不可以是num_cpus這是用于給定計(jì)算所需要的核心的。具體參考(128)

  • 此外還可以加入progress_bar,只有parallel 有.

最后

Linux 并行嵌套會(huì)報(bào)錯(cuò),子進(jìn)程不能有守護(hù)進(jìn)程。但是可以在循環(huán)之內(nèi)寫并行。

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

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