并发通信

多进程之间通信的限制

  • 进程之间是独立的,互不干扰的内存空间。
    我们先看个例子
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() #等待子进程执行完再继续执行
print(a)
image.png

通过上面2个例子运行结果分析:
按通常应该都是2,应该修改了全局变量值,但是这里只有子进程是2,主进程是1。
这是因为进程之间是独立的,互不干扰的内存空间,故子进程修改的,不影响主进程的。

进程间通信的解决方案

image.png
print('--------------进程间通信的解决方案--------------')

manager = multiprocessing.Manager()  #创建一个服务器进程,并返回与其通信的管理器
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() #等待子进程执行完再继续执行
print(list_proxy)

运行结果:
image.png
  • 一般常用的空间类型是:
    mgr.list()、mgr.dict()、mgr.Queue()

多线程之间通信的限制

注意:因为线程属于同一个进程,因此它们之间共享内存区域,因此全局变量是公共的。

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阻塞目的是为了让子进程执行完,最后能在主进程看到data,所以用join来阻塞

print(data)

image.png

加了n次减了n次,结果却为负数,按正常应该为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阻塞目的是为了让子进程执行完,最后能在主进程看到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

线程实现生产者-消费者模型


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) #创建0~99
            #只要队列没满,就向队列中添加数据
            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:
            #只要队列不为空,就从队列中取数据
            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

进程实现生产者-消费者模型


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) #创建0~99
            #只要队列没满,就向队列中添加数据
            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:
            #只要队列不为空,就从队列中取数据
            itme = self.queue.get()
            print('消费者-->消费:%s'%itme)
            time.sleep(1)

manager = multiprocessing.Manager()  #创建一个服务器进程,并返回与其通信的管理器

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

运行结果:
image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容

  • 必备的理论基础 1.操作系统作用: 隐藏丑陋复杂的硬件接口,提供良好的抽象接口。 管理调度进程,并将多个进程对硬件...
    drfung阅读 3,525评论 0 5
  • 本文是我自己在秋招复习时的读书笔记,整理的知识点,也是为了防止忘记,尊重劳动成果,转载注明出处哦!如果你也喜欢,那...
    波波波先森阅读 11,239评论 4 56
  • 七绝.贺成梅感恩酒会有感 文‖党爱元 各路亲朋人气旺, 灯光耀眼溢光芒。 美肴佳味心真切, 团队精神凝聚强。
    落寞在凉州的烟雨里阅读 326评论 0 1
  • 康熙皇帝得了一种怪病,宫中御医把所有的名贵药材都用遍了, 就是不见病情好转,他一怒之下停止了用药。这天,康熙独自出...
    转发件阅读 178评论 0 0
  • 又是一个谈论新老板和旧老板的时节,我知道你也经常会在私下谈论自己的老板,但像我这样有勇气公开的直白的残暴的谈论和比...
    blueYork阅读 623评论 0 4