1. 程式人生 > >python之多執行緒多程序併發通訊

python之多執行緒多程序併發通訊

1.獨立的程序記憶體空間與共享的伺服器程序空間

程序之間是:互不干擾的獨立記憶體空間

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2018/10/16 7:59
# @Author  : DoubleChina
# @Site    : 
# @File    : ConcurrentTest.py
# @Software: PyCharm
# 併發通訊
from multiprocessing import Process
a = 1
def func():
    global a
    a = 2
p = Process(target=func())
p.start()
p.join()
#輸出的是1,並不是2,兩個程序之間沒有共享記憶體
print(a)

解決了記憶體共享的問題

在這裡插入圖片描述

from multiprocessing import Process, Manager
#啟動伺服器程序
mgr = Manager()
#list、dict、queue
d = mgr.dict()
# d = dict()
print(type(d))


def func(d):
    d['a'] = 'a'


p = Process(target=func, args=(d,))
p.start()
p.join()
#{'a': 'a'}  ,伺服器程序間共享了資料
print(d)

一般常用的空間型別是:

  • mgr.list()
  • mgr.dict()
  • mgr.Queue()

##2.執行緒間共享的全域性變數與同步鎖的基本概念 因為執行緒屬於同一個程序,因此它們之間共享記憶體區域。因此全域性變數是公共的。

import threading
a = 1
def func():
    global a
    a = 2
t = threading.Thread(target=func)
t.start()
t.join()
#輸出2,共享了全域性變數
print(a)

多執行緒同時訪問一個變數,資源競爭導致資料異常

# 2個執行緒分別執行1萬次a+1
from threading import Thread

a = 0
n = 100000


def incr(n):
    global a
    for i in range(n):
        a = a + 1


def dncr(n):
    global a
    for i in range(n):
        a = a - 1


t1 = Thread(target=incr, args=(n,))
t2 = Thread(target=dncr, args=(n,))
t1.start()
t2.start()

t1.join()
t2.join()
#輸出不一定是0
print(a)

加鎖解決資源競爭問題

from threading import Thread, Lock
a = 0
n = 100000
lock = Lock()  # 建立鎖
def incr(n):
    global a
    for i in range(n):
        lock.acquire()  # 獲取鎖
        a = a + 1
        lock.release()  # 釋放鎖
def dncr(n):
    global a
    for i in range(n):
        lock.acquire()  # 獲取鎖,如果t1執行緒獲取了鎖,就會進入阻塞
        a = a - 1
        lock.release()  # 釋放鎖
t1 = Thread(target=incr, args=(n,))
t2 = Thread(target=dncr, args=(n,))
t1.start()
t2.start()
t1.join()
t2.join()
#輸出是0
print(a)

##3.執行緒與程序安全的佇列 佇列:一個入口,一個出口先入先出(FIFO) 在這裡插入圖片描述

執行緒佇列


# 執行緒佇列
import queue

q = queue.Queue(2)
q.put(1)
q.put(2)
# q.put(3, block=False)  # 阻塞
#獲取佇列
print(q.get())
# 測試佇列是否滿了
print(q.full())
# 判斷佇列是否是空的
print(q.empty())
# 佇列大小
print(q.qsize())
# 等待佇列完成
print(q.join())
# 任務結束:
print(q.task_done())

程序佇列


# 程序佇列
from  multiprocessing import Queue, Process

q = Queue()
q.put(1)


def func(q):
    # 佇列有資料,共享資源
    print(q.get())


p = Process(target=func, args=(q,))
p.start()
p.join()
# print(q.get())

如果只是一個執行緒/程序在使用,那麼它並不算公共資源。 但是一旦多個執行緒/程序在同時使用,那麼它就是一個公共資源。 如果被當作公共資源使用,那麼按理說是必須要加鎖的。但是,執行緒安全或程序安全的佇列中已經幫我們實現了鎖。因此我們不需要再自己使用鎖來同步。

4.消費者與生產者模式

生產者與消費者模型:其實是把一個需要程序通訊的問題分開考慮 生產者,只需要往佇列裡面丟東西(生產者不需要關心消費者) 消費者,只需要從佇列裡面拿東西(消費者也不需要關心生產者) 在這裡插入圖片描述


import threading
import random
import queue
import time


class Producer(threading.Thread):
    def __init__(self, queue):
        super().__init__()
        self.queue = queue

    def run(self):
        for i in range(10):
            r = random.randint(0, 9)
            if not self.queue.full():
                self.queue.put(r)
                print('佇列裡面添加了一個數據{}'.format(r))
                time.sleep(2)
            else:
                print('滿了')


class Consumer(threading.Thread):
    def __init__(self, queue):
        super().__init__()
        self.queue = queue

    def run(self):
        while True:
            # if not self.queue.empty():  # 判斷是否為空
            data = self.queue.get()
            time.sleep(2)
            print('從佇列裡面獲取資料{}'.format(data))
            self.queue.task_done()  # 通知佇列


if __name__ == '__main__':
    q = queue.Queue()
    p1 = Producer(q)
    c1 = Consumer(q)
    p1.start()
    c1.start()
    p1.join()
    c1.join()
    q.join()

程序&執行緒使用佇列

# 普通的佇列,不能用在多程序通訊
import queue
#在程序中使用Manager() 、 Queue()
from multiprocessing import Queue,Manager