午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

很多人現(xiàn)在還不知道的知識(shí)點(diǎn),Python多進(jìn)程和多線程詳解!

 怡紅公子0526 2020-05-25

1 單進(jìn)程單線程:一個(gè)人在一個(gè)桌子上吃菜。
2 單進(jìn)程多線程:多個(gè)人在同一個(gè)桌子上一起吃菜。
3 多進(jìn)程單線程:多個(gè)人每個(gè)人在自己的桌子上吃菜。

多線程的問題是多個(gè)人同時(shí)吃一道菜的時(shí)候容易發(fā)生爭搶,例如兩個(gè)人同時(shí)夾一個(gè)菜,一個(gè)人剛伸出筷子,結(jié)果伸到的時(shí)候已經(jīng)被夾走菜了。。。此時(shí)就必須等一個(gè)人夾一口之后,在還給另外一個(gè)人夾菜,也就是說資源共享就會(huì)發(fā)生沖突爭搶。

二、線程

threading是用來提供在一個(gè)進(jìn)程內(nèi)實(shí)現(xiàn)多線程的編程模塊.

前面我們學(xué)習(xí)了多進(jìn)程編程.

完成多任務(wù), 也可以在一個(gè)進(jìn)程內(nèi)使用多個(gè)線程. 一個(gè)進(jìn)程至少包括一個(gè)線程, 這個(gè)線程我們稱之為主線程. 在主線程中開啟的其他線程我們稱之為子線程.

一個(gè)進(jìn)程內(nèi)的所有線程之間可以直接共享資源, 所以線程間的通信要比進(jìn)程間通信方便了很多.

python的thread模塊是比較底層的模塊,python的threading模塊是對(duì)thread做了一些包裝的,可以更加方便的被使用

單線程示例:

import timedef say_sorry():
    print("親愛的,我錯(cuò)了,我能吃飯了嗎?")
    time.sleep(1)if __name__ == "__main__":    for i in range(5):
        say_sorry()

多線程示例:

import threadingimport timedef say_sorry():
    print("親愛的,我錯(cuò)了,我能吃飯了嗎?")
    time.sleep(1)if __name__ == "__main__":    for i in range(5):
        t = threading.Thread(target=say_sorry)
        t.start() #啟動(dòng)線程,即讓線程開始執(zhí)行

說明:

  1. 可以明顯看出使用了多線程并發(fā)的操作,花費(fèi)時(shí)間要短很多

  2. 創(chuàng)建好的線程,需要調(diào)用start()方法來啟動(dòng)

2.1 threading

Python3 線程中常用的兩個(gè)模塊為:

  • _thread

    thread 模塊已被廢棄。用戶可以使用 threading 模塊代替。所以,在 Python3 中不能再使用"thread" 模塊。為了兼容性,Python3 將 thread 重命名為 "_thread"

  • threading(推薦使用)

    threading用于提供線程相關(guān)的操作,線程是應(yīng)用程序中工作的最小單元。

2.2 Thread類

Thread類表示在單獨(dú)的控制線程中運(yùn)行的活動(dòng)。有兩種方法可以指定這種活動(dòng):

2.2.1、給構(gòu)造函數(shù)傳遞回調(diào)對(duì)象

mthread=threading.Thread(target=xxxx,args=(xxxx))
mthread.start()

2.2.2、在子類中重寫run() 方法  這里舉個(gè)小例子:

import threadingimport timeclass MyThread(threading.Thread):    def __init__(self,arg):
        super(MyThread, self).__init__()#注意:一定要顯式的調(diào)用父類的初始化函數(shù)。
        self.arg=arg    def run(self):#定義每個(gè)線程要運(yùn)行的函數(shù)
        time.sleep(1)
        print('the arg is:%s\r' % self.arg)for i in range(4):
    t =MyThread(i)
    t.start()

print('main thread end!')

2.2.3、多線程之間共享全局變量

多線程和多進(jìn)程最大的不同在于,多進(jìn)程中,同一個(gè)變量,各自有一份拷貝存在于每個(gè)進(jìn)程中,互不影響, 而多線程中,所有變量都由所有線程共享,下面觀察一下兩條線程中共享同一份數(shù)據(jù)。

from threading import Threadimport time 

g_num = 100		# 定義全局變量g_numdef work1():
    num = 1		# 定義局部變量num    global g_num		# 關(guān)鍵字global標(biāo)記全局變量g_num    for i in range(3):
        g_num += 1		# 更改全局變量的值
        print("---子線程1---work1函數(shù)---g_num:%d" % g_num)def work2():
    num = 2    global g_num		# 關(guān)鍵字global標(biāo)記全局變量g_num
    print("\t---子線程2---work2函數(shù)---個(gè)g_num:%d" % g_num)if __name__ == "__main__":
    print("啟動(dòng)線程之前:g_num:%d" % g_num)

    t1 = Thread(target=work1)    # 創(chuàng)建t1子線程,分配任務(wù)work1
    t2 = Thread(target=work2)    # 創(chuàng)建t2子線程,分配任務(wù)work2
    t1.start()  	# 啟動(dòng)t1線程

    time.sleep(1)	# 等待t1線程執(zhí)行完畢,觀察t2線程中打印的全局變量是否發(fā)生改變
    t2.start() 		# 啟動(dòng)t2線程

2.2.4、全局變量作為參數(shù)傳遞

將列表作為參數(shù)傳遞進(jìn)來,在參數(shù)末尾追加元素

from threading import Threadimport time

g_list = [10, 20, 30]def work1(list):    for i in range(3):
        list.append(i)    # 更改參數(shù)的值,在列表末尾追加元素
        print("--子線程1--work1----num:", list)def work2(list):
    print("\t--子線程2---work2---num:", list)if __name__ == "__main__":
    print("主線程訪問g_list:" , g_list)

    t1 = Thread(target=work1, args=(g_list,))    # 創(chuàng)建線程t1 將g_list作為參數(shù)傳遞進(jìn)去 執(zhí)行函數(shù)work1
    t2 = Thread(target=work2, args=(g_list,))    # 創(chuàng)建線程t2 將g_list作為參數(shù)傳遞進(jìn)去 執(zhí)行函數(shù)work2
    t1.start()

    time.sleep(1)
    t2.start()

將列表作為參數(shù)傳遞進(jìn)來,將參數(shù)重置

from threading import Threadimport time

g_list = [10, 20 ,30]def work1(list):    for i in range(3):        # list.append(i)
        list = [1, 2, 3]	# 重置參數(shù)
        print("--子線程1--work1----num:", list)def work2(list):
    print("\t--子線程2---work2---num:", list)if __name__ == "__main__":
    print("主線程訪問g_list:" , g_list)

    t1 = Thread(target=work1, args=(g_list,))	# 創(chuàng)建線程t1 將g_list作為參數(shù)傳遞進(jìn)去 執(zhí)行函數(shù)work1
    t2 = Thread(target=work2, args=(g_list,))	# 創(chuàng)建線程t2 將g_list作為參數(shù)傳遞進(jìn)去 執(zhí)行函數(shù)work2
    t1.start()  

    time.sleep(1)
    t2.start()  

2.2.5、線程的鎖

多線程和多進(jìn)程最大的不同在于,多進(jìn)程中,同一個(gè)變量,各自有一份拷貝存在于每個(gè)進(jìn)程中,互不影響,而多線程中,所有變量都由所有線程共享,所以,任何一個(gè)變量都可以被任何一個(gè)線程修改,因此,線程之間共享數(shù)據(jù)最大的危險(xiǎn)在于多個(gè)線程同時(shí)改一個(gè)變量,把內(nèi)容給改亂了。

來看看多個(gè)線程同時(shí)操作一個(gè)變量怎么把內(nèi)容給改亂了:

import time, threading# 假定這是你的銀行存款:
balance = 0def change_it(n):    # 先存后取,結(jié)果應(yīng)該為0:    global balance
    balance = balance + n
    balance = balance - ndef run_thread(n):    for i in range(100000):
        change_it(n)if __name__ == "__main__":
	t1 = threading.Thread(target=run_thread, args=(5,))
	t2 = threading.Thread(target=run_thread, args=(8,))
	t1.start()
	t2.start()
    t1.join()
    t2.join()
	
	print(balance)

每次執(zhí)行的結(jié)果不一定是個(gè)啥,究其原因,是因?yàn)樾薷?code>balance需要多條語句,而執(zhí)行這幾條語句時(shí),線程可能中斷,從而導(dǎo)致多個(gè)線程把同一個(gè)對(duì)象的內(nèi)容改亂了。

兩個(gè)線程同時(shí)一存一取,就可能導(dǎo)致余額不對(duì),你肯定不希望你的銀行存款莫名其妙地變成了負(fù)數(shù),所以,我們必須確保一個(gè)線程在修改balance的時(shí)候,別的線程一定不能改。

如果我們要確保balance計(jì)算正確,就要給change_it()上一把鎖,當(dāng)某個(gè)線程開始執(zhí)行change_it()時(shí),我們說,該線程因?yàn)楂@得了鎖,因此其他線程不能同時(shí)執(zhí)行change_it(),只能等待,直到鎖被釋放后,獲得該鎖以后才能改。由于鎖只有一個(gè),無論多少線程,同一時(shí)刻最多只有一個(gè)線程持有該鎖,所以,不會(huì)造成修改的沖突。創(chuàng)建一個(gè)鎖就是通過threading.Lock()來實(shí)現(xiàn):

#鎖的使用
mutex = threading.Lock()  #創(chuàng)建鎖
mutex.acquire([timeout])  #鎖定
mutex.release()  #釋放
import time, threading

balance = 0
lock = threading.Lock()def change_it(n):    # 先存后取,結(jié)果應(yīng)該為0:    global balance
    balance = balance + n
    balance = balance - ndef run_thread(n):    for i in range(100000):        # 先要獲取鎖:
        lock.acquire()        try:            # 放心地改吧:
            change_it(n)        finally:            # 改完了一定要釋放鎖:
            lock.release() 
            
if __name__ == "__main__":
	t1 = threading.Thread(target=run_thread, args=(5,))
	t2 = threading.Thread(target=run_thread, args=(8,))
	t1.start()
	t2.start()
    t1.join()
    t2.join()
	
	print(balance)

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多