1. 程式人生 > >並發編程之進程

並發編程之進程

實例化 情況 join() ini run __init__ 導致 linux下 搶票

一 、進程理論

    程序:一堆代碼

    進程:正在運行的程序

    進程是一個實體。每一個進程都有它自己獨立的內存空間

同步和異步:針對任務的提交方式

      同步:提交任務之後原地等待任務的返回結果,期間不做任何事

      異步:提交任務之後,不等待任務的返回結果,執行運行下一行代碼

阻塞與非阻塞:針對程序運行的狀態

      阻塞:遇到 io 操作 》》》阻塞態

      非阻塞:就緒或者運行態 》》》就緒態,運行態

二 、開啟進程的兩種方式(***)

    

    1、

from multiprocessing import Process
import time

def task(name):
print(‘%s is running‘%name)
time.sleep(3)
print(‘%s is over‘%name)


# 註意,在windows系統中,創建進程會將代碼以模塊的方式從頭到尾加載一遍
# 一定要寫在if __name__ == ‘__main__‘:代碼塊裏面
# 強調:函數名一旦加括號,執行優先級最高,立刻執行
if __name__ == ‘__main__‘:
p1 = Process(target=task,args=(‘egon‘,)) # 這一句話只是實例化了一個Process對象

p1.start() # 告訴操作系統創建一個進程
print(‘這是一個父程序‘)

    2、

from multiprocessing import Process
import time

class MyProcess(Process):

def __init__(self,name):
super().__init__()
self.name = name

# 必須寫run方法
def run(self):
print(‘%s is running‘%self.name)
time.sleep(1)
print(‘%s is end‘%self.name)

if __name__ == ‘__main__‘:
obj = MyProcess(‘egon‘)
obj.start()
print(‘這是一個父程序‘)

三 、進程對象的 join 方法(***)

from multiprocessing import Process
import time

def task(name,n):
print(‘%s is running‘%name)
time.sleep(n)
print(‘%s is over‘%name)


if __name__ == ‘__main__‘:
start_time = time.time()
p_list = []
for i in range(3):
p = Process(target=task,args=(‘子進程%s‘%i,i))

p.start()     # 千萬要知道,這句話只是告訴操作系統需要進程
        p_list.append(p)
for i in p_list:
i.join() # 主進程等待子進程結束 才繼續運行
   print(‘這是一個主程序‘,time.time()-start_time)

四 、 進程之間內存隔離(***)

from multiprocessing import Process

x = 100
def task():
global x
x =1

if __name__ == ‘__main__‘:
p = Process(target=task)
p.start()
p.join()
print(‘這是主程序‘,x)

進程是程序的執行單位,線程是CPU的執行單位。程序之間的數據是互相獨立運行的,因此進程運行的時候並不會影響其他進程,導致進程混亂。

五 、進程對象其他相關方法

from multiprocessing import Process,current_process
import time
import os

def task():
print(‘%s is running‘%os.getpid())
time.sleep(3)
print(‘%s is over‘%os.getppid())


if __name__ == ‘__main__‘:
p1 = Process(target=task)
p1.start()
# p1.terminate() # 殺死子進程
# time.sleep(0.1)
# print(p1.is_alive()) # 判斷子進程是否存活
print(‘主‘)

六 、僵屍進程與孤兒進程

        兩種情況下會回收子進程的 pid 等消息

            1 、父進程正常結束

            2 、join 方法

        孤兒進程:父進程意外死亡

        Linux下:init 孤兒福利院:用來回收孤兒進程所占用的資源

七 、守護進程:父進程結束了子進程必須也跟著結束

from multiprocessing import Process
import time

def task(name):
print(‘%s 正活著‘%name)
time.sleep(3)
print(‘%s 正常死亡‘%name)


if __name__ == ‘__main__‘:
p = Process(target=task,args=(‘egon總管‘,))
p.daemon = True # 必須在p.start開啟進程命令之前聲明
p.start()
print(‘皇帝jason正在死亡‘)

八 、互斥鎖(***) 千萬不要隨意使用,意思就是說能不用就盡量不用

  犧牲了效率但是保證了數據的安全

  鎖一定要在主進程中創建,給子進程去用

  解決多個進程操作同一份數據,造成數據不安全的情況

  加鎖會將並發變成串行

  鎖通常用在對數據操作的部分,並不是對進程全程加鎖

   

  mutex.acquire() # 搶鎖 一把鎖不能同時被多個人使用,沒有搶到的人,就一直等待鎖釋放
  buy(i)
  mutex.release() # 釋放鎖

關於搶票延遲的例子  

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

def search(i):
with open(‘info‘,‘r‘,encoding=‘utf-8‘) as f:
data = json.load(f)
print(‘用戶查詢余票數:%s‘%data.get(‘ticket‘))


def buy(i):
# 買票之前還得先查有沒有票!
with open(‘info‘,‘r‘,encoding=‘utf-8‘) as f:
data = json.load(f)
time.sleep(random.randint(1,3)) # 模擬網絡延遲
if data.get(‘ticket‘) >0:
data[‘ticket‘] -= 1 # 買票
with open(‘info‘,‘w‘,encoding=‘utf-8‘) as f:
json.dump(data,f)
print(‘用戶%s搶票成功‘%i)
else:
print("用戶%s查詢余票為0"%i)


def run(i,mutex):
search(i)
mutex.acquire() # 搶鎖 一把鎖不能同時被多個人使用,沒有搶到的人,就一直等待鎖釋放
buy(i)
mutex.release() # 釋放鎖


if __name__ == ‘__main__‘:
mutex = Lock()
for i in range(10):
p = Process(target=run,args=(i,mutex))
p.start()

並發編程之進程