python------併發編程

一 操做系統的做用:python

  1:隱藏醜陋複雜的硬件接口,提供良好的抽象接口算法

  2:管理、調度進程,而且將多個進程對硬件的競爭變得有序編程

二 多道技術: json

  1.產生背景:針對單核,實現併發windows

  ps:安全

  如今的主機通常是多核,那麼每一個核都會利用多道技術多線程

  有4個cpu,運行於cpu1的某個程序遇到io阻塞,會等到io結束再從新調度,會被調度到4個併發

  cpu中的任意一個,具體由操做系統調度算法決定。app

  2.空間上的複用:如內存中同時有多道程序dom

  3.時間上的複用:複用一個cpu的時間片

  強調:遇到io切,佔用cpu時間過長也切,核心在於切以前將進程的狀態保存下來,這樣 才能保證下次切換回來時,能基於上次切走的位置繼續運行

3、進程

  進程:正在進行的一個過程或者說一個任務。而負責執行任務的則是cpu

  程序:僅僅只是一堆代碼而已,而進程指的是程序的運行過程。

  須要強調的是:同一個程序執行兩次,那也是兩個進程,好比打開暴風影音,雖然都是同一個軟件,可是一個能夠播放大話西遊,一個能夠播放海賊王。

關於multiprocess模塊——綜合的、多元的 進程模塊(包):python中建立進程用來替我作事。

 

import os
from multiprocessing import Process  #導入進程模塊
import time
def func():
    time.sleep(2)
    print('子進程號%d'%os.getpid())


if __name__ =='__main__':
    p=Process(target=func)
    p.start()                                  #啓動子進程
    print('第一次主進程號%d'%os.getpid())
    p.join()                                              #阻塞
    print('第二次主進程號%d'%os.getpid())

 

有兩種狀況:

  一、沒有p.join()  :這種狀況下不阻塞,執行主程序,調用子進程。子進程和父進程是異步執行。

建立進程對象 傳要執行的函數 以及參數
進程對象.start()
主進程和子進程就是異步執行
若是主進程中的代碼已經結束了,子進程還沒結束,主進程會等待子進程

p.join 就是主進程會阻塞在join的位置,等待p進程結束
windows操做系統中 建立進程的語句必定要放在if __name__ == '__main__':條件語句下面

  二、有p.join():主進程阻塞在join的位置,等待p進程的結束(異步阻塞)

二、開啓多個子進程 

import os
import time
from multiprocessing import Process
def func(i):
    time.sleep(3)
    print('%d :子進程%d乾的事,父進程%d乾的事'%(i,os.getpid(),os.getppid()))

if __name__=='__main__':
    p_lst=[]
    for i in range(10):
        p=Process(target=func,args=(i,))     #實例化,調用線程類,傳參數
        p.start()                            #啓動線程(相似傳達一下消息
        p_lst.append(p) 
    for p in p_lst:
        p.join()                              #阻塞
    print('-------主進程-------')

  建立一個線程,而後啓動(對象名.start),它會在未知的時間裏建立線程,因此至於它是否是在主線程以前仍是以後啓動都不能肯定。若是想要主線程在全部線程後等待,那麼須要預先建立一個空列表,而後把全部啓動的子線程放入列表中,對列表中的子線程整體進行循環阻塞後,啓動主線程。

三、另外一種開啓多進程的方法

import os
from multiprocessing import Process
class MyProcess(Process):  #必須建立一個類,必須繼承Process方法
    def run(self):               #必須實現run方法
        print('子進程%d'%os.getpid())
        self.walk()
    def walk(self):
        print('子進程walk%d'%os.getpid())

if __name__ =='__main__':
    p=MyProcess()            #先實例化一個對象
    p.start()                   #啓動子進程
    p.join()
    print('主進程%d'%os.getpid())  #主進程

4.守護進程

  守護進程:守護進程會隨着主進程的代碼的結束而結束

  守護進程的做用:會隨着主進程的代碼執行結束而結束,不會等待其餘子進程

  守護進程要在start以前設置,在守護進程(也是個子進程)中,不能再開啓子進程。

import time
from multiprocessing import Process
def func():
    print('--'*10)
    time.sleep(15)
    print('--'*10)

def cal_time():
    while True:
        time.sleep(1)
        print('過去了1秒')

if __name__ == '__main__':
    p = Process(target=cal_time)
    p.daemon = True     # 必定在開啓進程以前設置
    p.start()
    p2 = Process(target=func)  # 15s
    p2.start()
    for i in range(100):    # 10s
        time.sleep(0.1)
        print('*'*i)
    p2.join()
View Code

鎖Lock:

  在併發編程中,爲了保證數據安全。加上鎖以後,每次須要等待數據被訪問完以後,才能繼續被其餘應用訪問。

import json
import time
import random
from multiprocessing import Lock
from multiprocessing import Process

def search(i):
    with open('ticket') as f:
        print(i,json.load(f)['count'])

def get(i):
    with open('ticket') as f:
        ticket_num = json.load(f)['count']
    time.sleep(random.random())
    if ticket_num > 0:
        with open('ticket','w') as f:
            json.dump({'count':ticket_num-1},f)
        print('%s買到票了'%i)
    else:
        print('%s沒票了'%i)

def task(i,lock):
    search(i)   # 查看票
    lock.acquire()                  #須要鎖
    get(i)      # 搶票
    lock.release()               #釋放鎖

if __name__ == '__main__':
    lock = Lock()            #實例化鎖
    for i in range(20):  # 20我的同時搶票
        p = Process(target=task,args=(i,lock))
        p.start()
鎖Lock

信號量:一把鑰匙多個鎖,能夠容許幾個進程同時訪問數據(數量是有限制的)

from multiprocessing import Semaphore
from multiprocessing import Process
import time
import random
def sing(i,sem):
    sem.acquire()
    print('%d進入KTV'%i)
    time.sleep(random.randint(1,10))
    print('%d離開ktv'%i)
    sem.release()

if __name__ =='__main__':
    sem=Semaphore(4)
    for i in range(20):
        Process(target=sing,args=(i,sem)).start()

 

 

4、併發與並行

  不管是並行仍是併發,在用戶看來都是'同時'運行的,不論是進程仍是線程,都只是一個任務而已,真是幹活的是cpu,cpu來作這些任務,而一個cpu同一時刻只能執行一個任務

    1 併發:是僞並行,即看起來是同時運行。單個cpu+多道技術就能夠實現併發,(並行也屬於併發)

       2  並行:同時運行,只有具有多個cpu才能實現並行

 

    單核下,能夠利用多道技術,多個核,每一個核也均可以利用多道技術(多道技術是針對單核而言的

 

      有四個核,六個任務,這樣同一時間有四個任務被執行,假設分別被分配給了cpu1,cpu2,cpu3,cpu4,

 

      一旦任務1遇到I/O就被迫中斷執行,此時任務5就拿到cpu1的時間片去執行,這就是單核下的多道技術

 

       而一旦任務1的I/O結束了,操做系統會從新調用它(需知進程的調度、分配給哪一個cpu運行,由操做系統說了算),可能被分配給四個cpu中的任意一個去執行

 

 

全部現代計算機常常會在同一時間作不少件事,一個用戶的PC(不管是單cpu仍是多cpu),均可以同時運行多個任務(一個任務能夠理解爲一個進程)。

 

  啓動一個進程來殺毒(360軟件)

 

  啓動一個進程來看電影(暴風影音)

 

  啓動一個進程來聊天(騰訊QQ)

 

  全部的這些進程都需被管理,因而一個支持多進程的多道程序系統是相當重要的

  多道技術概念回顧:內存中同時存入多道(多個)程序,cpu從一個進程快速切換到另一個,使每一個進程各自運行幾十或幾百毫秒,這樣,雖然在某一個瞬間,一個cpu只能執行一個任務,但在1秒內,cpu卻能夠運行多個進程,這就給人產生了並行的錯覺,即僞併發,以此來區分多處理器操做系統的真正硬件並行(多個cpu共享同一個物理內存)

5、同步/異步和阻塞/非阻塞

  同步:就是在發出一個功能調用時,在沒有獲得結果以前,該調用就不會返回。按照這個定義,其實絕大多數函數都是同步調用。可是通常而言,咱們在說同步、異步的時候,特指那些須要其餘部件協做或者須要必定時間完成的任務。

  異步:當一個異步功能調用發出後,調用者不能馬上獲得結果。當該異步功能完成後,經過狀態、通知或回調來通知調用者。若是異步功能用狀態來通知,那麼調用者就須要每隔必定時間檢查一次,效率就很低(有些初學多線程編程的人,總喜歡用一個循環去檢查某個變量的值,這實際上是一 種很嚴重的錯誤)。若是是使用通知的方式,效率則很高,由於異步功能幾乎不須要作額外的操做。至於回調函數,其實和通知沒太多區別。

  阻塞:是指調用結果返回以前,當前線程會被掛起(如遇到io操做)。函數只有在獲得結果以後纔會將阻塞的線程激活。有人也許會把阻塞調用和同步調用等同起來,實際上他是不一樣的。對於同步調用來講,不少時候當前線程仍是激活的,只是從邏輯上當前函數沒有返回而已。

  非阻塞:指在不能馬上獲得結果以前也會馬上返回,同時該函數不會阻塞當前線程。

小結:

  1. 同步與異步針對的是函數/任務的調用方式:同步就是當一個進程發起一個函數(任務)調用的時候,一直等到函數(任務)完成,而進程繼續處於激活狀態。而異步狀況下是當一個進程發起一個函數(任務)調用的時候,不會等函數返回,而是繼續往下執行當,函數返回的時候經過狀態、通知、事件等方式通知進程任務完成。

  2. 阻塞與非阻塞針對的是進程或線程:阻塞是當請求不能知足的時候就將進程掛起,而非阻塞則不會阻塞當前進程

相關文章
相關標籤/搜索