python🏅多線程超細詳解

本文已參與好文召集令活動,點擊查看:後端、大前端雙賽道投稿,2萬元獎池等你挑戰!html

項目中多線程的目的

具體原理我以爲這應該是能夠跳到操做系統裏面了一點點小小總結你們還能夠找本操做系統的書看看,老規矩找不到的話找我主頁,有一個關於資源的文章裏面有資源固然也能夠私信我。 咱們再說說咱們項目裏面用多線程的目的: 1.線程之間共享內存很是容易。 2·使用多線程來實現多任務併發執行比使用多進程的效率高 3·有時候能夠節省運行時間,這個一會在下面就會知道 4·當你一個文件要同時執行多個功能時就能夠用到多線程前端

python語言內置了多線程功能支持,而不是單純地做爲底層操做系統的調度方式,從而簡化了python的多線程編程。
複製代碼

實戰操做

說這麼多不如實際動手練練,首先導入線程 特別注意 :你們在見建文件的時候名字千萬別和導入的包threading同樣否則會出錯的。python

小知識

import threading
複製代碼

讓咱們先看看本身程序如今有多少個進程編程

import threading
def main():
    print(threading.current_thread())

if __name__ == '__main__':
    main()
複製代碼
結果:1#個人就一個你的呢?
複製代碼

若是你的進程不爲一的話還能夠這樣查看每個進程名後端

import threading
def main():
    print(threading.active_count())
    print(threading.enumerate())
   

if __name__ == '__main__':
    main()
複製代碼
>>>[<_MainThread(MainThread, started 36004)>]#返回的是一個列表由於個人目前就一個因此就一個主進程
複製代碼

還能夠查看正在運行的進程markdown

import threading
def main():
    print(threading.active_count())
    print(threading.enumerate())
    print(threading.current_thread())

if __name__ == '__main__':
    main()
複製代碼
>1
[<_MainThread(MainThread, started 36004)>]
<_MainThread(MainThread, started 36004)>

複製代碼

建立一個簡單的線程

首先咱們先介紹一下threading.Thread()裏面的參數,你們學python每一個模塊的功能時最好仍是看一下源文件內容,這樣有助於提升你的編程能力: 在這裏插入圖片描述多線程

須要注意的點我已經打上標記了併發

import threading
def first():
    print("frist active")
    print("frist finish")

def main():
    first_thread=threading.Thread(target=first,name="T1")
    first_thread.start()#開始的標誌
    print("main")

if __name__ == '__main__':
    main()
複製代碼
結果:
第一次運行
frist active
main
frist finish
第二次運行
frist active
frist finish
main

複製代碼

每次的結果不同就已經代表Frist和main是同時運行的了。 若是說效果不太明顯的話,咱們改進一下接下來咱們引入函數

import time
複製代碼
import threading
import time
def first():
    print("frist active")
    time.sleep(3)
    print("frist finish")

def main():
    first_thread=threading.Thread(target=first,name="T1")
    first_thread.start()
    print("main")

if __name__ == '__main__':
    main()
複製代碼
結果:
frist active
main
frist finish
複製代碼

由於執行到Frist active的時候Frist線程要睡3秒這個時候main還在執行因此這樣每次都是這個結果了。 特別強調target=first不是導入Frist函數從源文件咱們就已經看出是經過run()方法進行的,這裏解釋我引用一位大佬解釋 在這裏插入圖片描述oop

連接

這位大佬你們應該都熟悉,就是頂頂大名的雷學委各位大佬能夠去他的主頁看看可能會學到些新知識 固然若是你以爲這樣不行的話你也能夠重寫threading.Thresd裏的run方法來個自定義線程

class MyThread(threading.Thread):
        def __init__(self,n):
            super(MyThread,self).__init__()   #重構run函數必須寫
            self.n = n

        def run(self):
            print('task',self.n)
            time.sleep(1)
            print('2s')
            time.sleep(1)
            print('1s')
            time.sleep(1)
            print('0s')
            time.sleep(1)

    if __name__ == '__main__':
        t1 = MyThread('t1')
        t2 = MyThread('t2')
        t1.start()
        t2.start()
複製代碼
結果:
task t1
task t2
2s
2s
1s
1s
0s
0s
複製代碼

守護線程

所謂’線程守護’,就是主線程無論該線程的執行狀況,只要是其餘子線程結束且主線程執行完畢,主線程都會關閉。也就是說:主線程不等待該守護線程的執行完再去關閉。
複製代碼

很差理解的話來看看例子

import threading
import time
def first():
    print("frist active")
    time.sleep(3)
    print("frist finish")

def second():
    print("second active")
    print("second finish")

def main():
    first_thread=threading.Thread(target=first,name="T1")
    second_thresd=threading.Thread(target=second,name="T2")
    first_thread.setDaemon(True)#必定要在start()前開始
    first_thread.start()
    second_thresd.start()
    print("main")

if __name__ == '__main__':
    main()
    

複製代碼
結果
frist active
second active
second finishjiemeijieshu
main

複製代碼

當主線程和其餘子線程都結束無論守護線程first_thread 結沒結束程序都結束 當設second_thresd爲守護線程的時候狀況是這樣的

import threading
import time
def first():
    print("frist active")
    time.sleep(3)
    print("frist finish")

def second():
    print("second active")
    print("second finish")

def main():
    first_thread=threading.Thread(target=first,name="T1")
    second_thresd=threading.Thread(target=second,name="T2")
    second_thresd.setDaemon(True)#必定要在start()前開始
    first_thread.start()
    second_thresd.start()
    print("main")

if __name__ == '__main__':
    main()
    


複製代碼
frist active
second active
second finish
main
frist finish #儘管輸出這個要等三秒
複製代碼

主進程等待子進程結束

爲了讓守護線程執行結束以後,主線程再結束,咱們可使用join方法,讓主線程等待子線程執行

import threading
import time
def first():
    print("frist active")
    time.sleep(3)
    print("frist finish")

def second():
    print("second active")
    print("second finish")

def main():
    first_thread=threading.Thread(target=first,name="T1")
    second_thresd=threading.Thread(target=second,name="T2")
    first_thread.start()
    second_thresd.start()
    first_thread.join()

    print("main")

if __name__ == '__main__':
    main()
    


複製代碼
結果:
frist active
second active
second finish
frist finish
main
不加join是這樣的結果
frist active
second active
second finish
main
frist finish
複製代碼

共享全局變量的特性

這裏定義一個全局變量A

import threading
import time
def first():
    global A
    print("frist active")
    time.sleep(3)
    A=A+3
    print("frist:%d"%A)
    print("frist finish")

def second():
    global A
    print("second active")
    A=A+6
    print("second:%d"%A)
    print("second finish")

def main():
    global A
    first_thread=threading.Thread(target=first,name="T1")
    second_thresd=threading.Thread(target=second,name="T2")
    first_thread.start()
    second_thresd.start()
    #first_thread.join()

    print("main")
    A=A+3
    print("mian:%d"%A)

if __name__ == '__main__':
    A=0
    main()




複製代碼

來看一下結果

frist active
second active
second:6
second finish
main
mian:9
frist:12
frist finish
複製代碼

由上面的例子能夠看出,輸出A的值的時候不一樣進程之間的資源是共享的這就致使了變量A的值不固定形成了髒數據的狀況,不理解的話咱們就來個例子。 在這裏插入圖片描述

在沒有互斥鎖的狀況下,假設帳戶有一萬元錢,存錢和取錢同時進行可能帳戶餘額會有一萬一千元。這樣我固然高興只是銀行不答應。爲了不這種狀況咱們引入鎖的概念,下面咱們簡單的介紹幾種編程裏面經常使用的。

互斥鎖

import threading
import time
def first():
    global A,lock
    lock.acquire()
    print("frist active")
    time.sleep(3)
    A=A+3
    print("frist:%d"%A)
    print("frist finish")
    lock.release()

def second():
    global A,lock
    lock.acquire()
    print("second active")
    A=A+6
    print("second:%d"%A)
    print("second finish")
    lock.release

def main():
    global A,lock
    lock=threading.Lock()
    first_thread=threading.Thread(target=first,name="T1")
    second_thresd=threading.Thread(target=second,name="T2")
    first_thread.start()
    second_thresd.start()
    #first_thread.join()

    print("main")
    A=A+3
    print("mian:%d"%A)

if __name__ == '__main__':
    A=0
    main()

複製代碼

結果

frist active
main
mian:3
frist:6
frist finish
second active
second:12
second finish

複製代碼

是否是這樣看着就舒服多了,若是例子不夠明顯咱們再來一個

import threading
import time
def first():
    global A,lock
    lock.acquire()
    print("frist active")
    time.sleep(3)
    A=A+3
    print("frist1:%d"%A)
    A = A + 3
    print("frist2:%d" % A)
    print("frist finish")
    lock.release()

def second():
    global A,lock
    lock.acquire()
    print("second active")
    A=A+6
    print("second1:%d"%A)
    A=A+6
    print("second2:%d"%A)

    print("second finish")
    lock.release()

def main():
    global A,lock
    lock=threading.Lock()
    first_thread=threading.Thread(target=first,name="T1")
    second_thresd=threading.Thread(target=second,name="T2")
    first_thread.start()
    second_thresd.start()
    #first_thread.join()

    print("main")
    A=A+3
    print("mian:%d"%A)

if __name__ == '__main__':
    A=0
    main()

複製代碼

結果

frist active
main
mian:3
frist1:6
frist2:9
frist finish
second active
second1:15
second2:21
second finish

去掉鎖之後結果

frist active
second active
second1:6
second2:12
second finish
main
mian:15
frist1:18
frist2:21
frist finish

複製代碼

很明顯去掉鎖之後結果雜亂的很

信號量

我相信對操做系統有必定了解的確定,在剛纔提到鎖的時候就想到了信號量畢竟考研題常常會出現,同步,互斥和信號量機制。咱們就來講一說信號量鎖,其實道理很簡單假如你如今,在中國結婚了你只能娶一個老婆吧,儘管你能夠去找別的女人但他們不能稱爲老婆她們會被稱爲小三,二奶啊等等,這裏老婆這個信號量在中國就是==一==只能有一個,別的再來就不能夠了。

import threading
import time

def run(n,semaphore):
    semaphore.acquire()   #加鎖
    time.sleep(3)
    print('run the thread:%s\n' % n)
    semaphore.release()    #釋放


if __name__== '__main__':
    num=0
    semaphore = threading.BoundedSemaphore(3)   #最多容許3個線程同時運行
    for i in range(10):
        t = threading.Thread(target=run,args=('t-%s' % i,semaphore))
        t.start()
    while threading.active_count() !=1:
        pass
    else:
        print('----------all threads done-----------')

複製代碼

結果

run the thread:t-2
run the thread:t-1


run the thread:t-0

run the thread:t-3
run the thread:t-5
run the thread:t-4



run the thread:t-6

run the thread:t-7

run the thread:t-8

run the thread:t-9

----------all threads done-----------

複製代碼

送點資源

肥學以爲python裏面這些操做仍是有點簡單的,若是各位大佬想繼續深究線程又沒有資源的話能夠我這裏有一本關於操做系統的書,領取能夠私信我哦,好了今天的學習就到這裏吧別忘了==點贊三聯哦==

相關文章
相關標籤/搜索