1. 程式人生 > 其它 >程式碼建立程序、join、程序和互斥鎖

程式碼建立程序、join、程序和互斥鎖

  • 程式碼建立程序

  • join方法

  • 程序間資料預設隔離

  • 程序物件相關屬性和方法

  • 殭屍程序和孤兒程序

  • 守護程序

  • 互斥鎖

一、程式碼建立程序

""" 
1.建立程序的方式
    滑鼠雙擊桌面一個應用圖示
    程式碼建立
    
建立程序的本質:
     在記憶體中要一塊記憶體空間用來執行相應的程式程式碼
    """
# multiprocessing 程序模組
# Process P是大寫
from multiprocessing import Process
import time

def task(name):
    print('%s is runing'% name)
    time.sleep(3)
    print('%s is over'% name)


if __name__ == '__main__':
    p = Process(target=task, args= ('owen', ))
    p.start()
    print('主程序')

from multiprocessing import Process
import time
class MyProcess(Process):
    def __init__(self, username):
        self.username =username
        super().__init__()
    def run(self):
        print('嘿嘍哇', self.username)
        time.sleep(3)
        print('再會', self.username)
if __name__ == '__main__':
    p = MyProcess('owen')
    p.start()
    print('主程序')

  • 程序實現併發

# 它的實現就是將於客戶端通訊的程式碼封裝稱為一個函式, 之後來一個客戶就建立一個程序,專門服務

# 服務端
import socket
from multiprocessing import Process

def get_server():
    server = socket.socket()
    server.bind(('127.0.0.1', 9999))
    server.listen(5)
    return server

# 將服務客戶端的程式碼封裝成函式(通訊程式碼)
def talk(sock):
    while True:
        data = sock.recv(1024)
        print(data.decode('utf8'))
        sock.send(data.upper())  # 接收值傳送大寫

if __name__ == '__main__':
    server = get_server()
    while True:
        sock, addr = server.accept()
        p = Process(target=talk, args=(sock, ))
        p.start()

# 客戶端
import socket

client = socket.socket()
client.connect(('127.0.0.1', 9999))

while True:
    client.send(b'hello')
    data = client.recv(1024)
    print(data.decode('utf8'))

二、join方法

# join方法就是讓主程序等待子程序程式碼執行完畢之後 再執行
from multiprocessing import Process
import time

def task(name, n):
    print(f'{name} is running')
    time.sleep(n)
    print(f'{name} is over')

if __name__ == '__main__':
    p1 = Process(target=task, args=('cuihua', 1))
    p2 = Process(target=task, args=('xiongda', 2))
    p3 = Process(target=task, args=('guangtouqiang', 3))
    start_time = time.time()
    p1.start()
    p2.start()
    p3.start()
    p1.join()
    p2.join()
    p3.join()
    end_time = time.time() - start_time
    print('主程序', f'總耗時:{end_time}')
  # 主程序 總耗時:3.0834152698516846

如果想要p.start()之後的程式碼, 等待子程序全部執行結束之後再列印
   1.直接sleep,但是這個方法肯定不可行,因為子程序執行時間不可控
    2.join方法
      針對多個子程序的等待

三、程序間資料預設隔離

# 我們可以把記憶體看成很對個小房間組成的, 一人一個互不干擾
from multiprocessing import Process

money = 100

def task():
    global money  # 區域性改全域性申明
    money = 222

if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    p.join()
    print(money)
# 同一臺計算機上面,程序和程序之間是資料隔離的

四、程序物件屬性和方法

"""
 檢視程序號的方法:
     windows: tasklist 結果集中PID
     mac:  ps -ef
"""

1.1、檢視程序號
  courrent_process函式
  from multiprocessing import Process, current_process
print(current_process().pid)  # 13236

# 獲取程序號的目的就是可以通過程式碼的方式管理程序
windows系統: taskkill關鍵字
Mac/linux系統: kill關鍵字

1.2、os模組
  os.getpid()  # 獲取當前程序的程序號
  os.getppid() # 獲取到當前程序的父程序號

2.殺死子程序
  terminate()   # 這個過程可能需要一點時間
3.判斷子程序是否存活
  is_alive()  # 返回True或者False

五、殭屍程序和孤兒程序

殭屍程序
   所有的子程序在執行結束之後都會程式設計殭屍程序(死了沒死透)
   因為還保留著pid和一些執行過程的中的記錄便於主程序檢視(只是短時間儲存)
    等這些資訊被主程序回收,就徹底死了
    1.主程序正常結束
    2.呼叫join方法
    # 殭屍程序是無害的
孤兒程序
  # 子程序存在,但是父程序斃了
  子程序會被作業系統自動接管

六、守護程序

"""
  守護就是生死全靠守護的物件,對生守生, 對死守死
"""

from multiprocessing import Process
import time

def task(name):
    print(f'御用特使:{name}還沒死')
    time.sleep(3)
    print(f'御用特使:{name}死了')

if __name__ == '__main__':
    p = Process(target=task, args=('黑大帥', ))
    p.daemon = True  # 將子程序設定為守護程序,主程序結束,子程序立即結束
    p.start()
    print('皇上斃了')
# p.daemon = True 一定要放在p.start()上面

七、互斥鎖*

import json
from multiprocessing import Process
import time
import random

# 設定票數,一張
ticket_data.json : {"ticket_num": 1}
# 查票功能
def search(name):
    with open(r'ticket_data.json', 'r', encoding='utf8') as f:
        data = json.load(f)
    print(f'{name}查詢餘額為:%s'% data.get('ticket_num'))

# 買票功能
def buy(name):
    # 先查一下票數
    with open(r'ticket_data.json', 'r', encoding='utf8') as f:
        data = json.load(f)
    time.sleep(random.randint(1, 3))  # 停留1~3秒
    # 判斷
    if data.get('ticket_num') > 0:
        data['ticket_num'] -= 1
        with open(r'ticket_data.json', 'w', encoding='utf8') as f:
            json.dump(data, f)
        print(f'{name}搶票成功')
    else:
        print(f'{name}搶票失敗,票已經沒了')

# 將買票封裝成函式
def run(name):
    search(name)
    buy(name)

# 模擬多人同時
if __name__ == '__main__':
    for i in range(1, 6):
        p = Process(target=run, args=('使用者:%s' % i, ))
        p.start()
        
使用者:2查詢餘額為:2
使用者:1查詢餘額為:2
使用者:3查詢餘額為:2
使用者:5查詢餘額為:2
使用者:4查詢餘額為:2
使用者:4搶票成功使用者:5搶票成功

使用者:2搶票成功
使用者:1搶票成功
使用者:3搶票成功
#  結果很明顯,是錯亂的,而且都5個人買一張都成功了
"""
  在多個程序操作同一個資料的時候會造成資料的錯亂, 所以我們需要增加一個加鎖處理(互斥鎖)
  將併發變成序列, 效率低了,但安全性高了
  互斥鎖並不能輕易使用, 容易造成死鎖現象
  互斥鎖旨在處理資料的部分加鎖, 不能什麼地方都加

"""
# 增加互斥鎖
from multiprocessing import Process, Lock
mutex = Lock()
mutex.acquire()  # 上鎖
mutex.release()  # 解鎖

# 將買票封裝成函式
def run(name,mutex):
    search(name)
    mutex.acquire()  # 上鎖
    buy(name)
    mutex.release()  # 解鎖

# 模擬多人同時
if __name__ == '__main__':
    mutex = Lock()
    for i in range(1, 6):
        p = Process(target=run, args=('使用者:%s' % i, mutex))
        p.start()


使用者:1查詢餘額為:2
使用者:2查詢餘額為:2
使用者:3查詢餘額為:2
使用者:4查詢餘額為:2
使用者:5查詢餘額為:2
使用者:1搶票成功
使用者:2搶票成功
使用者:3搶票失敗,票已經沒了
使用者:4搶票失敗,票已經沒了
使用者:5搶票失敗,票已經沒了
    
    
"""
  行鎖: 針對行數加鎖, 同一時間只能一個人操作
  表鎖: 針對表資料加鎖, 同一時間只能一個人操作
"""