python 併發的開端

網絡併發

進程的基礎

​ 1.程序linux

​ 一堆靜態的代碼文件程序員

​ 2.進程編程

​ 一個正在運行的程序windows

​ 由操做系統操控調用交由cpu運行 ,被cpu運行設計模式

2.操做系統

​ 1。管理控制協調計算機中硬件與軟件的關係安全

​ 2。操做系統的做用?網絡

​ 2.沒有操做系統:大家在開發軟件多線程

​ 第一層。對硬件(cpu,內存,磁盤)協調,調用併發

​ 第二層 如何調用接口去編程

第一個做用:將一些對硬件操做的複雜醜陋的接口, 變成簡單美麗的接口,open函數

第二個做用:多個進程搶佔一個(cpu)資源時,操 做系統會將你的執行變得合理有序,雨露均沾(比較 快感覺不到)

阻塞:input read write sleep recv accept sendto recvfrom 。。。

操做系統的發展史

百萬級代碼 寫的系統

多道技術

最先出現的計算機:算盤

電子類的計算機發展史

第一代計算機1940~1955(手工操做----穿孔卡片

在大學裏出現了機房,想使用計算機必須預定

先鏈接調配各個硬件,1.5小時,真空管,而後在插上程序調試,效率低

優勢:我的獨享整個計算機資源

缺點;1.硬件條件插線,耗時

​ 2.全部人串行執行

第二代 1955~1965 磁帶存儲--批處理系統

優勢程序員不用親自對硬件進行插線操控,效率提升

能夠進行批量處理代碼

缺點:

1.程序員不能肚子使用計算機

2.你的全部程序仍是串行

1566184846415

第三代集成電路,多道程序系統(1955~1965)

1.集成電路:把所用的硬件變小,線路板

2.將兩套不一樣的生產線合併成一個生產線

技術上的更新:多道技術,操做系統的理念

​ 空間上的複用

​ 將一個內存能夠同時加載多個進程

​ 時間上的複用

​ 實現將cpu在多個進程之間來回切換,而且保留狀態,在切回來還能保持原樣

幾乎全部的程序都會有io阻塞

同時加載到內存 3個任務,3個進程,每一個進程都有阻塞狀況,只要cpu運行一個進程時,遇到阻塞立馬會切換,長時間佔用cpu也會切換

提高效率,最大限度的使用cpu

若是是一個IO(阻塞)密集型進程,來回切換提高效率

若是在一個計算密集型,耗時來會切換下降效率

第三代計算機 普遍採用必須的保護硬件(程序之間的內存彼此隔離)以後,推進第三代計算機應用而生

每一個人佔用計算機的時間有限的

多人(少於10個)共同使用一個計算機主機

第四代計算機:至今

面向字:大型的科學計算機

面向字符:商用計算機

進程的理論(重點)

2.操做系統

​ 1。管理控制協調計算機中硬件與軟件的關係

​ 2。操做系統的做用?

​ 2.沒有操做系統:大家在開發軟件

​ 第一層。對硬件(cpu,內存,磁盤)協調,調用

​ 第二層 如何調用接口去編程

第一個做用:將一些對硬件操做的複雜醜陋的接口, 變成簡單美麗的接口,open函數

第二個做用:多個進程搶佔一個(cpu)資源時,操 做系統會將你的執行變得合理有序,雨露均沾(比較 快感覺不到)

多道技術

​ 空間上的複用

​ 將一個內存能夠同時加載多個進程

​ 時間上的複用

​ 實現將cpu在多個進程之間來回切換,而且保留狀態,在切回來還能保持原樣

當進程遇到IO阻塞,或者長時間運行,操做系統會將此進程颳起,保留狀態,會將cpu強行切換到另外一個進程

進程之間的通訊方式

串行:全部的任務(進程)一個一個完成

併發:一個cpu完成多個任務,在不一樣的任務中來回切換,看起來是同時完成的

並行:多個cpu執行多個任務,真正的同時完成

阻塞:cpu遇到io就是阻塞

非阻塞:沒有IO叫非阻塞

程序:一堆靜態文件

一個正在執行的程序任務,一個進程

一個程序可否同時開啓多個進程?能夠

進程的建立(進程之間不容許通訊)

一個子進程必須基於主進程

主進程是啓動子進程的

一個主進程能夠開啓多個子進程。

unix:fork建立子進程

uninx(linux,mac):建立一個子進程會完徹底全複製一個主進程全部的資源,初始資源不變。

windows:操做系統調用CreateProcess處理進程的建立

windows:建立一個子進程,會copy主進程全部的資源,可是會改變一些資源

系統是最主進程

進程的狀態

1566190822509

運行程序運行到io進行阻塞 程序進入阻塞狀態

阻塞結束進入就緒態 須要在就緒態等待開始運行 等程序遇到io阻塞再進行運行

併發編程:多進程

某特破賽腎multiprocesssing模塊 用來開啓子進程

進程建立的兩種方式()開闢須要的時間長

建立子進程須要時間 有時間停滯 會調用

p.start 是一個建立聲明copy一份,一個cpu是併發

這個信號操做系統接收到以後,會從內存中開闢一個子進程空間,而後·在將主進程全部數據進行深copy加載到子進程 而後運行子進程

Process類的介紹

強調:

參數介紹

1.須要使用關鍵字的方式來指定參數

2.target是指定子進程要執行的任務(函數名),

3.args是函數的位置參數(實參以元組的形式)

4.name是(函數)子進程的名稱

5.group參數未使用,值始終未None

方法

1.p.star()啓動進程,並調用該子進程的p.run()
2.p.run():進程啓動運行的方法,是它去調用target指定的函數,咱們自定義類的類
3.p.terminate():強制終止進程p,不會進行任何清理操做,若是p建立了子進程,該子進程就成了殭屍進程,使用該方法須要特別當心這種狀況。若是p還保存了一個鎖那麼也將不會被釋放,進而致使死鎖
4.p.is_alive():若是p仍然運行,返回True

5.p.join([timeout]):主線程等待p終止(強調:是主線程處於等的狀態,而p是處於運行的狀態)。timeout是可選的超時時間,須要強調的是,p.join只能join住start開啓的進程,而不能join住run開啓的進程

進程的屬性介紹:

1.p.daemon:默認值爲False,若是設爲True,表明p爲後臺運行的守護進程,當p的父進程終止時,p也隨之終止,而且設定爲True後,p不能建立本身的新進程,必須在p.start()以前設置

2.p.name:進程的名稱

3.p.pid:進程的pid

4.p.exitcode:進程在運行時爲None、若是爲–N,表示被信號N結束(瞭解便可)

5.p.authkey:進程的身份驗證鍵,默認是由os.urandom()隨機生成的32字符的字符串。這個鍵的用途是爲涉及網絡鏈接的底層進程間通訊提供安全性,這類鏈接只有在具備相同的身份驗證鍵時才能成功(瞭解便可)

第一個方式

from multiprocessing import Process
import time
def ppt(name):
    print(f'{name}is running')
    time.sleep(2)
    print(f'{name}is gone')
if __name__ == '__main__':
    ppt()pp2()pp3()#串行運行

    p=Process(target=ppt,args=('長鑫',))#對應一個target 是對應一個方法 args==是傳入的值
    p.start()#啓動進程
    print('===煮開水')
    time.sleep(3)

第二種方式

第二種#默認的用類run
from multiprocessing import Process
import time
class MYprocess(Process):#process是父類
    def __init__(self):#必須調用父類的init實現
         super().__init__()#執行父類的init
         self.name=name
    def run(self):#必須是run要不會繼承父類的run
        print(f'{self.name}is running')
        print(f'{self.name}is gone')
if __name__ == '__main__':
    p=MYprocess()#建立一個進程對象(子程序)
    p2=MYprocess()#建立一個進程對象(子程序)
    p.start()#時間會有時間延遲#聲明開闢一個子進程的空間會把主進程的初始值深copy下來 
    p.start()#由於會有時間延遲
    print('===主')#先走這、、

1566266779340

會引用父類的init 要運行本地的init 要使用父類的super.init()

子類沒有用父類的 必須有run

tasklist命令行查看全部進程的pid

進程的pid是進程的惟一標識 運行一次開闢一次

import os

print(os.getpid())#每次獲取的id都不一樣的(子進程)

如何在子進程得到主進程的pid

import os
print(os.getppid())#每次獲取的id都不一樣的(父進程)

子進程的名字會改變子進程深copy過來的主進程的名字 不會改變原有的名字

空間隔離

進程與進程之間是由物理隔離:不能共享內存數據(lsook 隊列)

#空間隔離
from multiprocessing import Process
import time
name=[1,2]
def ppt():    
    name.append(1)    
    print(name)
    if __name__ == '__main__':    
        # ppt()pp2()pp3()串行運行
        p=Process(target=ppt)
        #對應一個target 是對應一個方法 args==是傳入的值    
        p.start()    
        time.sleep(3)    
        print(f'主{name}')#子程序深copy 會有空間隔離

import是模塊後面的屬性

進程對象join方法

join讓主進程等待子進程運行結束以後在運行主程序

join就是阻塞 主程序有join就會阻塞等待對應子進程運行完

同時開啓 前面執行後面也在執行讀秒 join是結束 會阻塞

join
from multiprocessing import Process
import time
def task(sec):
    print('is,running')
    time.sleep(sec)
    print('is gone')
if __name__ == '__main__':
    start_time=time.time()
p1=Process(target=task,args=(6,))
p2=Process(target=task,args=(7,))
p3=Process(target=task,args=(8,))
p1.start()#同時執行
p2.start()#同時執行
p3.start()#同時執行  
p1.join()#遇到阻塞 等待執行完
end_name = time.time() - start_time
print(end_name)###
p2.join()
end_name = time.time() - start_time
print(end_name)
p3.join()
end_name=time.time()-start_time
print(end_name)

進程對象其餘屬性

from multiprocessing import Process
import time
import os

def task(n):
    time.sleep(3)
    print('%s is running' %n,os.getpid(),os.getppid())

if __name__ == '__main__':
    p1 = Process(target=task,args=(1,),name = '任務1')
        p1.start()
    # p1.terminate()
    # time.sleep(2)  # 睡一會,他就將個人子進程殺死了#沒有直接殺死。
    # print(p1.is_alive())  # False#判斷子程序是不是活着的
  -------------------------------------
    #更名字
    # print(p1.name) # 給子進程起名字
    # for i in range(3):
    #     p = Process(target=task, args=(1,))
    #     print(p.name)  # 給子進程起名字

代碼示例

守護進程

daemon

版本一

from multiprocessing import Process
import time
class MYprocess(Process):
    # def __init__(self,name):#必須調用父類的init實現
    #     super().__init__()#
    #     self.name=name
    def run(self):#必須是run要不會繼承父類的run
        print(f'{self.name}is running')
        print(f'{self.name}is gone')
if __name__ == '__main__':
    p=MYprocess()
    p,daemon=True#要在設置執行子進程以前設置成守護進程
    p1.start()#時間會有時間延遲
    p.start()#由於會有時間延遲
    print('===主')#先走這、、
    #主進程結束子進程也結束

子進程守護着守護主進程,只要主進程結束

版本二

#主進程代碼運行完畢,守護進程就會結束
from multiprocessing import Process
from threading import Thread
import time
def foo():
    print(123)
    time.sleep(1)
    print("end123")

def bar():
    print(456)
    time.sleep(3)
    print("end456")
if __name__ == '__main__':#必需要有--main

    p1=Process(target=foo)
    p2=Process(target=bar)

    p1.daemon=True
    p1.start()
    p2.start()
    # p1.join()
    # p2.join()
    print("main-------") #打印該行則主進程代碼結束,則守護進程p1應該被終止,可能會有p1任務執行的打印信息123,由於主進程打印main----時,p1也執行了,可是隨即被終止
#隨着守護的主進程的結束而結束了

殭屍進程

殭屍進程與孤兒進程

  1. 主進程須要等待子進程結束以後,主進程才結束

  2. 主程序時刻監測子進程的運行狀態,當子進程結束以後,一段時間,將子進程回收

    爲何主程序不在子進程結束後對其回收

    1.主進程與子進程是異步關係,主進程沒法立刻捕獲子進程何時結束

    2.若是子進程結束以後立刻再內存釋放資源,主進程就沒有辦法檢測子進程的狀態

unix針對於上面的問題提供一個機制

全部的字節內存結束以後,會立馬釋放掉文件的操做鏈接,內存的大部分數據,可是會保留一些內容:進程號,結束時間,運行狀態,等待主進程檢測,回收

殭屍進程:

當子進程結束以後,在被主進程回收以前,都會進入殭屍進程狀態

不是所有子進程結束

殭屍進程有無危害?

若是父進程不對殭屍進程進行回收(wait/waitpid),會產生大量的殭屍進程,這樣就會佔用內存,佔用進程pid

孤兒進程:

父進程因爲某種緣由,結束了,可是你的子進程還在運行中,這樣你的這些子進程就成了孤兒進程,你的父進程若是結束,你的全部的孤兒進程就會被init進程回收,init就變成了他們的主進程

出現殭屍進程如何解決?

父進程產生了大量子進程,子程序結束可是不回收,這樣就會造成大量的殭屍進程,解決方式殭屍直接殺死父進程,將全部的殭屍進程變成孤兒進程,由init進行回收

互斥鎖(lock)

併發是效率優先,需求是順序優先,

多個進程共搶一個資源,要保證順序優先,併發是效率優先,需求是順序優先,串行,是一個一個來

強制順序優先用join串行強制性排序不合理,爲保證公平,應該是先到先得

何時用互斥鎖

多個任務共搶同一個資源(數據),若是你想要順序優先(數據安全),必定要讓其串行

互斥鎖的做用

犧牲效率保證數據安全

把子程序變成串行

能夠把串行變得合理有序,保證公平,先到先得 能夠把部分變成串行

一把互斥鎖鎖不能連續鎖 只能鎖一次

互斥鎖必須成對出現

from multiprocess import Lock
    lock.acquire()  
    lock.release()

acquire上鎖,release開鎖

# 三個同事 同時用一個打印機打印內容. # 三個進程模擬三個同事, 輸出平臺模擬打印機.
# 版本一: 
# from multiprocessing import Process 
# import time 
# import random 
# import os 
# # def task1(): 
#     print(f'{os.getpid()}開始打印了') 
#     time.sleep(random.randint(1,3)) 
#     print(f'{os.getpid()}打印結束了') 
# # def task2():
#     print(f'{os.getpid()}開始打印了')
#     time.sleep(random.randint(1,3))
#     print(f'{os.getpid()}打印結束了') 
# # def task3(): 
#     print(f'{os.getpid()}開始打印了')
#     time.sleep(random.randint(1,3)) 
#     print(f'{os.getpid()}打印結束了') 
# 
# if __name__ == '__main__': 
# 
#     p1 = Process(target=task1) 
#     p2 = Process(target=task2)
#     p3 = Process(target=task3) # 
#     p1.start() 
#     p2.start() 
#     p3.start()
# 如今是全部的進程都併發的搶佔打印機, 
# 併發是以效率優先的,可是目前咱們的需求: 順序優 先. 
# 多個進程共強一個資源時, 要保證順序優先: 串行,一 個一個來.
# 版本二:
# from multiprocessing import Process 
# import time 
# import random 
# import os 
# # def task1(p): 
#     print(f'{p}開始打印了') 
#     time.sleep(random.randint(1,3)) 
#     print(f'{p}打印結束了') 
# # def task2(p):
#     print(f'{p}開始打印了') 
#     time.sleep(random.randint(1,3)) 
#     print(f'{p}打印結束了') # # def task3(p): 
#     print(f'{p}開始打印了')
#     time.sleep(random.randint(1,3)) 
#     print(f'{p}打印結束了') 
# # if __name__ == '__main__':
# #     p1 = Process(target=task1,args= ('p1',)) 
#     p2 = Process(target=task2,args= ('p2',)) 
#     p3 = Process(target=task3,args= ('p3',)) 
# #     p2.start() 
#     p2.join() 
#     p1.start() 
#     p1.join() 
#     p3.start() 
#     p3.join()
# 咱們利用join 解決串行的問題,保證了順序優先,可是 這個誰先誰後是固定的. # 這樣不合理. 你在爭搶同一個資源的時候,應該是先到 先得,保證公平.
# 版本3:
from multiprocessing 
import Process from multiprocessing 
import Lock 
import time 
import random 
import os
def task1(p,lock):    
    '''    一把鎖不能連續鎖兩次    
    lock.acquire()    
    lock.acquire()    
    lock.release()    
    lock.release()    
    '''    
    lock.acquire()    
    print(f'{p}開始打印了')    time.sleep(random.randint(1,3))    
    print(f'{p}打印結束了')    
    lock.release()
def task2(p,lock):    
    lock.acquire()    
    print(f'{p}開始打印了')    time.sleep(random.randint(1,3))    
    print(f'{p}打印結束了')    
    lock.release()
def task3(p,lock):    
    lock.acquire()    
    print(f'{p}開始打印了')    time.sleep(random.randint(1,3))    
    print(f'{p}打印結束了')    
    lock.release()
if __name__ == '__main__':
    mutex = Lock()    
    p1 = Process(target=task1,args= ('p1',mutex))
  lock與join的區別. 共同點: 均可以把併發變成串行, 保證了順序. 不一樣點: join人爲設定順序,lock讓其爭搶順序,保證了公 平性.   
        3. 進程之間的通訊: 進程在內存級別是隔離的,可是文件在磁盤上, 
            1. 基於文件通訊. 利用搶票系統講解.
    p2 = Process(target=task2,args= ('p2',mutex))    p3 = Process(target=task3,args= ('p3',mutex))
    p2.start()    
    p1.start()    
    p3.start()

鎖總結,

當不少進程共搶一個資源(數據)時,你要保證順序(數據的安全必定要串行),

join和鎖的區別

join

咱們利用join 解決串行的問題,保證了順序優先

會合理的對子進程進程排序根據運行的速度和操做系統的阻塞進行排隊 保證公平不強制固定

舉例查票

# 版本二:
# from multiprocessing import Process 
# import time 
# import random 
# import os 
# # def task1(p): 
#     print(f'{p}開始打印了') 
#     time.sleep(random.randint(1,3)) 
#     print(f'{p}打印結束了') 
# # def task2(p):
#     print(f'{p}開始打印了') 
#     time.sleep(random.randint(1,3)) 
#     print(f'{p}打印結束了') # # def task3(p): 
#     print(f'{p}開始打印了')
#     time.sleep(random.randint(1,3)) 
#     print(f'{p}打印結束了') 
# # if __name__ == '__main__':
# #     p1 = Process(target=task1,args= ('p1',)) 
#     p2 = Process(target=task2,args= ('p2',)) 
#     p3 = Process(target=task3,args= ('p3',)) 
# #     p2.start() 
#     p2.join() 
#     p1.start() 
#     p1.join() 
#     p3.start() 
#     p3.join()
# 咱們利用join 解決串行的問題,保證了順序優先,可是 這個誰先誰後是固定的. 
# 這樣不合理. 你在爭搶同一個資源的時候,應該是先到 先得,保證公平.

隊列(至關於一個容器)

隊列和管道都是將數據存放於內存中

咱們應該儘可能避免使用共享數據,儘量使用消息傳遞和隊列,避免處理複雜的同步和鎖問題,並且在進程數目增多時,每每能夠得到更好的可獲展性。

from multiprocessing import Process,Queue
import random
import time
import os
lis=[]
def search(mete):
    time.sleep(random.randint(1,5))
    s=mete.get()
    mete.put(s)
    print(f'手機尾號{os.getpid()}的用戶查看了,還剩餘名額{s}')
    # print(lis)

def paid(mete,mete1):
    time.sleep(random.randint(1,3))
    s=mete.get()
    if int(s)>0:
        s-=1
        mete.put(s)
        phone=os.getpid()
        print(f'手機尾號{phone}得到了手機名額剩餘{s}')
        mete1.put(phone)
    else:
        # mete1.get()
        # lis.append(mete1.get())
        # print(f'{lis}恭喜以上得到名額')
        print(f'手機尾號{os.getpid()}沒有獲得名額')
        mete.put(s)
def task(mete,lis):
    search(mete)
    paid(mete,lis)
if __name__ == '__main__':
    mete=Queue()
    mete1=Queue(10)
    mete.put(10)
    lst =[]
    for i in range(30):
        p=Process(target=task,args=(mete,mete1))#傳入了兩個管道
        p.start()
        lst.append(p)
    for i in lst:
        i.join()

    while 1:
        try:
            print(mete1.get(block=False))
        except Exception:
            break

隊列是串行,誰先拿到誰在前面

put往隊列裏面放值 get把值取出刪除**

先進先出

消費者和生產者模型

編程思想,模型,設計模式,理論都是給你一種編程的方法,之後相似的狀況,套用便可

模型三要素

生產者:產生數據的

消費者:接受數據作進一步處理的

容器:盆(隊列)

隊列起到什麼做用

容器耦合性過強沒有,起到緩衝的做用,平衡生產力與消費力,解耦

from multiprocessing import Process
from multiprocessing import Queue
import time
import random

def producer(q,name):#利用for循環 傳入
    for i in range(1,6):#生成6個
        time.sleep(random.randint(1,2))
        res=f'{i}號包子'
        q.put(res)#把6傳進去
        print(f'生產者{name}生產了{res}')
def  consumer(q,name):
    while 1:
        try:
            food=q.get(timeout=3)
            time.sleep(random.randrange(1,4))
            print(f'\033[31;0m消費者{name}吃了{food}\033[0m')
        except Exception:
            return
if __name__ == '__main__':
    q=Queue()
    p1=Process(target=producer,args=(q,'孫宇'))
    p2=Process(target=consumer,args=(q,'海狗'))
    p1.start()
    p2.start()

具備阻塞的幾個方法

線程

什麼是線程

一條流水線的工做流程。

進程:在內存中開啓一個進程空間,而後將主進程的全部數據複製一份

而後調用線程去執行代碼

執行角度(線程)

運行過程自己叫作線程

同一個線程資源共用 執行是進程的代碼

資源角度(進程)

是cpu最小的執行單位

資源單位,一個進程存在至少存在主線程

進程是一個資源單位 是一個獨立的資源 有空間隔離

若是想要通訊 須要利用queue

在內存中申請一塊空間把代碼放進去cpu調用內存空間的代碼的過程

運行的過程還會使用進程中的資源

描述具體開啓一個進程

開啓一個進程:進程會在內存中開闢一個進程空間,將主進程的資料數據所有複製一份,線程會執行裏面的代碼

線程vs進程

進程

子進程是先運行主進程全部程序

線程

線程先加載主進程裏面的代碼

線程速度快 併發同時執行兩個任務 共用資源

不會複製

  1. 開啓進程的開銷很是大,比開啓線程的開銷大不少
  2. 開啓線程的速度很是快,要快幾十倍到上百倍
  3. 線程和線程之間能夠共享數據,進程與進程以前需藉助隊列等方法實現通訊(線程數據共享,進程數據不共享)

線程的應用

澀乳癌的thread

同一進程內的資源數據對於多個線程來講是共享的

線程裏面pid就是一個主進程的pid

from threading import Thread
def task(name):
    print(os.getpid())#主進程的pid
if __name__ == '__main__':

    t1=Thread(target=task,args=('海狗',))
    t1.start()
    print('===主線程')

線程沒有pid 主進程開闢子進程比較耗時

併發:一個cpu執行多個任務,看起來像是同時執行多個任務

單個進程開啓三個線程,併發的執行任務

開啓三個進程併發的執行任務

主進程須要等待線程結束

主線程子線程沒有地位之分,可是,一個進程誰在幹活?一個主線程在幹活,當幹完活了。等待其餘線程幹完活以後,才能結束本進程

3.開啓線程的兩種方式

線程沒有主次之分 兩種方式函數和類

不須要main 寫了好區分 nnnnnn

'''
基於函數的
'''
from threading import Thread
import time

def task(name):
    print(f'{name}is running')
    time.sleep(1)
    print(f'{name}is gone')
if __name__ == '__main__':

    t1=Thread(target=task,args=('海狗',))
    t1.start()
    print('===主線程')
#基於類
from threading import Thread
import time
class func(Thread):
    def __init__(self,name):
        super().__init__()
        self.name=name
    print(1)
    def run(self):
        print(self.name)
if __name__ == '__main__':#這句話能夠不寫 由於線程沒有主次之分只是多開一個線程 

    t1=Thread(target=func,args=('立業',))
    t1.start()
    print('主線程')

進程vs線程代碼

1.速度對比(主進程必定在子進程以前)(線程速度快 先執行子線程,在執行主進程)

2.線程裏面pid就是一個主進程的pid,線程裏面沒有pid

3.同一進程內的資源數據對於多個線程來講是共享的

線程的其餘方法(瞭解)

也可使用進程裏面的方法

join是同樣 的 都是等待子線程(進程)結束

daemon 守護進程 主線程執行完就結束了

Thread實例對象的方法
  # isAlive(): 返回線程是否活動的。
  # getName(): 返回線程名。
  # setName(): 設置線程名。

threading模塊提供的一些方法:
  # threading.currentThread()同等與current_thread(): 返回當前的線程變量。
  # threading.enumerate(): 返回一個包含正在運行的線程的list。正在運行指線程啓動後、結束前,不包括啓動前和終止後的線程。
  # threading.activeCount(): 返回正在運行的線程數量,與len(threading.enumerate())有相同的結果。
from mulitprocessing import Process
from threading import Thread
# from threading import Thread
# from threading import currentThread
# from threading import enumerate
# from threading import activeCount
# import os
# import time
#
# x = 3
# def task():
#     # print(currentThread())
#     time.sleep(1)
#     print('666')
# print(123)
# if __name__ == '__main__':
#
#     t1 = Thread(target=task,name='線程1')
#     t2 = Thread(target=task,name='線程2')
#     # name 設置線程名
#     t1.start()
#     t2.start()
#     # time.sleep(2)
#     # print(t1.isAlive())  # 判斷線程是否活着
#     # print(t1.getName())  # 獲取線程名
#     # t1.setName('子線程-1')
#     # print(t1.name)  # 獲取線程名  ***
#
#     # threading方法
      # print(current_thread().name)
#     # print(currentThread())  # 獲取當前線程的對象
#     # print(enumerate())  # 返回一個列表,包含全部的線程對象
#     print(activeCount())  # ***
#     print(f'===主線程{os.getpid()}')

守護線程

t.daemon#t.setDaemon(true)

守護線程:若是守護線程的生命週期小於其餘線程,則他確定結束

線程速度快 因此主線程結束以前會先執行線程 最後和主線程一塊兒結束,

主線程結束條件是 全部子線程結束 由於資源共用 主進程不能結束

from threading import Thread
 import time


 def sayhi(name):
     print('你滾!')
     time.sleep(2)
     print('%s say hello' %name)

 if __name__ == '__main__':
     t = Thread(target=sayhi,args=('egon',))
     # t.setDaemon(True) #必須在t.start()以前設置
     t.daemon = True
     t.start()  # 線程的開啓速度要跟進程開不少

     print('主線程')

線程互斥鎖

爲何數據不會持續更新

線程比較快 線程同時操做一個數據 全部開啓的一個子線程都會先拿到初始值 進行操做

不加鎖

from threading import Thread
import time

x = 100
def task():
    global x
    temp = x
    time.sleep(0.1)
    temp -= 1
    x = temp



if __name__ == '__main__':
    t_l1 = []
    for i in range(100):
        t = Thread(target=task)
        t_l1.append(t)
        t.start()

    for i in t_l1:
        i.join()
    print(f'主{x}')

不加鎖搶佔同一個資源的問題

加鎖

from threading import Thread
from threading import Lock
import time

x = 100
lock = Lock()

def task():
    global x
    lock.acquire()
    temp = x
    time.sleep(0.1)
    temp -= 1
    x = temp
    lock.release()


if __name__ == '__main__':
    t_l1 = []
    for i in range(100):
        t = Thread(target=task)
        t_l1.append(t)
        t.start()

    for i in t_l1:
        i.join()
    print(f'主{x}')

同步鎖保證數據安全

死鎖現象

鎖套鎖現象

遞歸鎖(RLOCK)

解決死鎖現象 會有一個計數器,能夠連續加鎖加一次計數器加一,計數器變爲別人才能搶

from threading import Thread,Lock
import time
from threading import RLock
lock_A=lock_B=RLock()
lock_A1=Lock()
lock_B1=Lock()
class func(Thread):
    def run(self):
        self.f1()
        self.f2()
    def f1(self):
        lock_A.acquire()
        print(f'{self.name}拿到了A鎖')
        lock_B.acquire()
        print(f'{self.name}拿到了B鎖')
        lock_B.release()
        lock_B.release()
    def f2(self):
        lock_B.acquire()
        print(f'{self.name}拿到了B鎖')
        lock_A.acquire()
        print(f'{self.name}拿到了A鎖')
        lock_A.release()
        lock_B.release()
if __name__ == '__main__':
    for i in  range(3):
        t=func()
        t.start()

信號量(Semaphore)三破

Semaphore信號量

容許多個線程 使用信號量 控制併發次數

GIL鎖全局解釋器鎖

創py 空間,開啓一個進程

py解釋器,py文件都會加載進去

Cpython自帶GIL鎖

單個進程多線程是併發執行,執行的時候會加鎖,執行到io阻塞會掛起,把鎖打開,

cpu切換到後面的線程會繼續執行,

cpyhon爲何加鎖?

​ 1.當時都是單核時代,並且cpu價格很是貴

​ 2.若是不加全局鎖解釋器鎖,開發Cpython解釋器的程序源就會在源碼內部各類主動加鎖,解鎖,很是麻煩,各類死鎖現象等待,他爲了省事兒,直接進入解釋器時給線程加一個鎖

1566531288680

優勢:

保證解釋器Cpython的解釋器的數據資源的安全。

缺點:

單個進程的多線程不能利用多核

Jpython沒有鎖

pypy沒有GIL鎖

多核時代,我將Cpython的GIL鎖去掉行麼?

由於Cpython解釋器全部業務邏輯都是圍繞單個線程實現的,去掉這個GIL鎖,幾乎不可能

單個進程的多線程能夠併發,可是不能利用多核,不能並行

多個進程能夠併發,並行

io密集型:

遇到io阻塞cpu就會切換 空間複用 阻塞結束 GIL鎖加上繼續執行,執行完釋放GIL鎖

單個進程的多線程合適,併發

計算密集型:

由於併發效果 線程運行一段時間 cpu會進行強行切換

多進程是能夠並行(調用多個cpu)的

GlL與lock鎖的區別

相同點:都是同種鎖,互斥鎖

不一樣點:

GIL鎖全局解釋器鎖,保護解釋器內部的資源數據的安全。

GlL鎖上鎖,釋放鎖無需手動操做

​ 本身代碼中的互斥鎖保護進程中資源的安全

​ 本身定義的互斥鎖必須本身手動上鎖釋放鎖

驗證計算密集型,IO密集型的效率

代碼驗證:

計算密集型

開啓多進程合適 多進程(併發,並行)比單進程多線程(併發)快效率高

io密集型

單個進程的多線程的併發

多線程實現socket通訊

線程不用mian裏建立

不管是多線程還剩多進程,若是按照上面的寫法

來一我的客戶端請求,我就開一個線程(進程),來一個請求開一個線程(進程)請求

應該是這樣的:你的計算機容許範圍內,開啓的線程進程數量越多越好

相關文章
相關標籤/搜索