并發(fā)通信

多進程之間通信的限制

  • 進程之間是獨立的,互不干擾的內存空間。
    我們先看個例子
a = 1  #定義全局變量
def func():
    global a
    a=2     #修改全局變量值
    print(a)

func()
print(a)

運行結果:


image.png

再看利用進程運行的例子:

import multiprocessing

a = 1  #定義全局變量

def func():
    global a
    a=2     #修改全局變量值
    print(a)

process = multiprocessing.Process(target=func)
process.start()
process.join() #等待子進程執(zhí)行完再繼續(xù)執(zhí)行
print(a)
image.png

通過上面2個例子運行結果分析:
按通常應該都是2,應該修改了全局變量值,但是這里只有子進程是2,主進程是1。
這是因為進程之間是獨立的,互不干擾的內存空間,故子進程修改的,不影響主進程的。

進程間通信的解決方案

image.png
print('--------------進程間通信的解決方案--------------')

manager = multiprocessing.Manager()  #創(chuàng)建一個服務器進程,并返回與其通信的管理器
list_proxy = manager.list()  #通過管理器在服務器進程中開辟一個列表空間,并返回一個代理
print(list_proxy)   #用法和list一樣


def func2(list):
    list.append('a')
    print(list)

#把代理傳給子進程,子進程里就可以通過這個代理,來操作共享空間來進行通信
process2 = multiprocessing.Process(target=func2, args=(list_proxy,))
process2.start()
process2.join() #等待子進程執(zhí)行完再繼續(xù)執(zhí)行
print(list_proxy)

運行結果:
image.png
  • 一般常用的空間類型是:
    mgr.list()、mgr.dict()、mgr.Queue()

多線程之間通信的限制

注意:因為線程屬于同一個進程,因此它們之間共享內存區(qū)域,因此全局變量是公共的。

import threading

a = 1
def func3():
    global a
    a = 2
    print(a)
thread = threading.Thread(target=func3)
thread.start()
thread.join()
print(a)

運行結果:
image.png

但是多線程間共享內存間存在競爭問題。

print('--------------多線程共享內存間存在競爭問題--------------')
import threading

data = 0
n = 100000

def add(n):
    global data
    for i in range(n):
        data +=i

def sub(n):
    global data

    for i in range(n):
        data -=i

t_add = threading.Thread(target=add, args=(n,))
t_sub = threading.Thread(target=sub, args=(n,))
t_add.start()
t_sub.start()
t_add.join()
t_sub.join()   #這2個地方加join阻塞目的是為了讓子進程執(zhí)行完,最后能在主進程看到data,所以用join來阻塞

print(data)

image.png

加了n次減了n次,結果卻為負數(shù),按正常應該為0。
使用鎖來控制共享資源的訪問。

print('--------------使用鎖來控制共享資源的訪問--------------')

import threading

data = 0
n = 1000000

lock = threading.Lock() #生成一把鎖

def add(n):
    global data
    for i in range(n):
        # lock.acquire()   #加鎖
        # data +=i
        # lock.release()   #釋放鎖
        #可以寫生上下文格式
        with lock:
            data +=i

def sub(n):
    global data

    for i in range(n):
        # lock.acquire()   #加鎖
        # data -=i
        # lock.release()   #釋放鎖
        with lock:
            data -=i

t_add = threading.Thread(target=add, args=(n,))
t_sub = threading.Thread(target=sub, args=(n,))
t_add.start()
t_sub.start()
t_add.join()
t_sub.join()   #這2個地方加join阻塞目的是為了讓子進程執(zhí)行完,最后能在主進程看到data,所以用join來阻塞

print(data)

運行結果:
image.png

這樣才達到目的,就像去銀行存錢取錢,存取不多不少!

線程與進程的安全隊列

隊列:先進先出,一個入口,一個出口。
image.png
  • 線程安全隊列操作
    queue.Queue:
    入隊: put(item)
    出隊: get()
    測試空: empty() # 近似
    測試滿: full() # 近似
    隊列長度: qsize() # 近似
    任務結束: task_done()
    等待完成: join()
  • 進程安全隊列操作
    mgr.Queue:
    入隊: put(item)
    出隊: get()
    測試空: empty() # 近似
    測試滿: full() # 近似
    隊列長度: qsize() # 近似

進程比線程少了task_done()和 join()方法。

生產者和消費者模型

所謂,生產者與消費者模型,本質上是把進程通信的問題分開考慮生產只需要往隊列里面丟東西(生產者不需要關心消費者)消費者,只需要從隊列里面拿東西(消費者也不需要關心生產者)。


image.png

image.png

線程實現(xiàn)生產者-消費者模型


print('--------------生產者與消費者模型--------------')
'''
所謂,生產者與消費者模型,本質上是把進程通信的問題分開考慮
生產者,只需要往隊列里面丟東西(生產者不需要關心消費者)
消費者,只需要從隊列里面拿東西(消費者也不需要關心生產者)
'''

print('--------------多線程的消費者與生產者模式--------------')
'''
生產者:沒滿,則生產,只關心隊列是否已滿。滿了就阻塞。
消費者:只關心隊列是否為空。不為空,則消費,為空則阻塞。

'''
import threading
import queue
import random
import time

class Producer(threading.Thread):  #生產者
    def __init__(self, queue):
        super().__init__()
        self.queue = queue
    def run(self):
        while True:
            item = random.randint(0, 10) #創(chuàng)建0~99
            #只要隊列沒滿,就向隊列中添加數(shù)據(jù)
            self.queue.put(item)
            print('生產者-->生產:%s'%item)
            time.sleep(1)

class Customer(threading.Thread):
    def __init__(self, queue):
        super().__init__()
        self.queue = queue
    def run(self):
        while True:
            #只要隊列不為空,就從隊列中取數(shù)據(jù)
            itme = self.queue.get()
            print('消費者-->消費:%s'%itme)
            time.sleep(1)

q =queue.Queue(5)  #長度為5
producer = Producer(q)
custormer = Customer(q)
producer.start()
custormer.start()
producer.join()

運行結果:
image.png

進程實現(xiàn)生產者-消費者模型


import multiprocessing
import queue
import random
import time

class Producer(multiprocessing.Process):  #生產者
    def __init__(self, queue):
        super().__init__()
        self.queue = queue
    def run(self):
        while True:
            item = random.randint(0, 10) #創(chuàng)建0~99
            #只要隊列沒滿,就向隊列中添加數(shù)據(jù)
            self.queue.put(item)
            print('生產者-->生產:%s'%item)
            time.sleep(1)

class Customer(multiprocessing.Process):
    def __init__(self, queue):
        super().__init__()
        self.queue = queue
    def run(self):
        while True:
            #只要隊列不為空,就從隊列中取數(shù)據(jù)
            itme = self.queue.get()
            print('消費者-->消費:%s'%itme)
            time.sleep(1)

manager = multiprocessing.Manager()  #創(chuàng)建一個服務器進程,并返回與其通信的管理器

q =manager.Queue(5)  #長度為5
producer = Producer(q)
custormer = Customer(q)
producer.start()
custormer.start()
producer.join()

運行結果:
image.png
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 必備的理論基礎 1.操作系統(tǒng)作用: 隱藏丑陋復雜的硬件接口,提供良好的抽象接口。 管理調度進程,并將多個進程對硬件...
    drfung閱讀 3,568評論 0 5
  • 本文是我自己在秋招復習時的讀書筆記,整理的知識點,也是為了防止忘記,尊重勞動成果,轉載注明出處哦!如果你也喜歡,那...
    波波波先森閱讀 11,299評論 4 56
  • 七絕.賀成梅感恩酒會有感 文‖黨愛元 各路親朋人氣旺, 燈光耀眼溢光芒。 美肴佳味心真切, 團隊精神凝聚強。
    落寞在涼州的煙雨里閱讀 341評論 0 1
  • 康熙皇帝得了一種怪病,宮中御醫(yī)把所有的名貴藥材都用遍了, 就是不見病情好轉,他一怒之下停止了用藥。這天,康熙獨自出...
    轉發(fā)件閱讀 184評論 0 0
  • 又是一個談論新老板和舊老板的時節(jié),我知道你也經常會在私下談論自己的老板,但像我這樣有勇氣公開的直白的殘暴的談論和比...
    blueYork閱讀 662評論 0 4