Python好文有约简友广场

Python(三十一)并发通信

2021-12-03  本文已影响0人  Lonelyroots

进程和线程主要是用来提高效率和分担任务的,但他们还有待完善,接下来我将具体介绍进程间的通信隔离与线程间的资源争夺,以及如何解决这两个问题。

1. 进程相互通信

1.1. 进程间的通信隔离

管理器用来通信,代理(公共服务器)来操作。


1.2. 通信解决办法

import multiprocessing
mg = multiprocessing.Manager()       # 创建一个公共服务器进程,返回与主进程的代理
var = 10

def func(list1):
    global var
    var += 1
    print('func:',var)
    list1.append(var)

li = mg.list()       # 开辟一个列表空间,多个进程可以一起使用的
p1 = multiprocessing.Process(target=func, args=(li,))
p1.start()
p1.join()
print('outer:', var)        # 不通过公共服务器,outputs:outer: 10
print('outer:', li)     # 通过公共服务器,outputs:outer: [11]

multiprocessing.Manager():创建一个公共服务器进程,返回与主进程的代理,是进程间通信的常用解决方案,通过公共空间来实现进程间的通信。

2. 线程相互通信

2.1. 线程共享变量

对于线程而言,它们始终在一个进程当中,因此共享同一个内存空间,因此可以访问主进程中的数据。

"""线程没有通信隔离,不需要公共服务器"""
import threading

var = 10

def func():
    global var
    var += 1
    print('func:',var)
    return var

t1 = threading.Thread(target=func)
t1.start()
t1.join()
print('outer:',var)

2.2. 线程资源争夺问题

2.2.1. 线程资源争夺问题

当计算量过大时,会出现资源错误,因为CPU计算式多条指令,组合运行的,所以在运行过程中如果插入其它指令,就会造成不可预见的效果。

2.2.2. 互斥锁

对于特殊资源,可以用锁来保护资源,确保每次操作的完整性。

"""
线程有的时候运行会错乱:(线程争夺)
    但用互斥锁会耗费时间,所以使用的比较少
"""
import threading

var =100
lock = threading.Lock()        # 互斥锁

def func1():
    global var
    for i in range(100000):
        lock.acquire()      # 上锁
        var += 1
        lock.release()      # 解锁

def func2():
    global var
    for i in range(100000):
        lock.acquire()      # 上锁
        var -= 1
        lock.release()      # 解锁

t1 = threading.Thread(target=func1)
t2 = threading.Thread(target=func2)
t1.start()
t2.start()
t1.join()
t2.join()
print(var)

3. 队列

3.1. 队列概念

队列:先进先出

3.2. 队列的实现

import queue:导入队列模块
q=queue.Queue(4):设置的队列长度,这里表示设置4,当存放数量大于队列长度时,会发生阻塞。
q.put('a'):存入a,b、c、d与a相同,当到e时,会报错,因为超过了队列长度。


q.get():依次取出队列里的数,当取数大于队列长度时,会发生阻塞。
q.empty():可通过该指令查看当前队列是否为空。
q.full():可通过该指令查看当前队列是否满。
q.qsize():可通过该指令查看当前队列的数量。

4. 生产者与消费者模型

4.1. 基本概念


生产者和消费者模型:
queue.Queue()线程队列只在主进程里面,不能使用在进程和进程的交互中

"""
生产者和消费者模型:
    queue.Queue()线程队列只在主进程里面,不能使用在进程和进程的交互中
"""
import threading
import queue
import time

q = queue.Queue(4)      # 设置线程队列长度为4

class Consumer(threading.Thread):       # 继承了线程类
    # 消费者
    def __init__(self,q):
        super().__init__()      # 让Consumer成为一个线程对象,重写线程类的init方法
        self.queue = q

    def run(self):
        while True:
            # 消费者逻辑 不需要考虑生产者 只需要获取队列中的任务即可
            res = self.queue.get()      # 获取任务
            print(f'消费了数据{res*100}')

class Producer(threading.Thread):
    # 生产者
    def __init__(self,q):
        super().__init__()
        self.queue = q

    def run(self):
        # 生产者逻辑 不需要考虑消费者,只需要往队列中添加任务
        import random
        while True:
            time.sleep(1)
            res = random.randint(1,100)
            print(f'生产了数据{res}')
            self.queue.put(res)     # 提交任务

pr = Producer(q)
cu = Consumer(q)
pr.start()
cu.start()

生产者和消费者模型:
multiprocessing.Queue该进程队列能使用在进程和进程的交互中

"""
生产者和消费者模型:
    multiprocessing.Queue该进程队列能使用在进程和进程的交互中
"""
import multiprocessing
import queue
import time

q = multiprocessing.Queue(4)        # 设置进程队列长度为4

class Consumer(multiprocessing.Process):       # 继承了进程类
    # 消费者
    def __init__(self,q):
        super().__init__()      # 让Consumer成为一个进程对象,重写进程类的init方法
        self.queue = q

    def run(self):
        while True:
            # 消费者逻辑 不需要考虑生产者 只需要获取队列中的任务即可
            res = self.queue.get()      # 获取任务
            print(f'消费了数据{res*100}')

class Producer(multiprocessing.Process):
    # 生产者
    def __init__(self,q):
        super().__init__()
        self.queue = q

    def run(self):
        # 生产者逻辑 不需要考虑消费者,只需要往队列中添加任务
        import random
        while True:
            time.sleep(1)
            res = random.randint(1,100)
            print(f'生产了数据{res}')
            self.queue.put(res)     # 提交任务

pr = Producer(q)
cu = Consumer(q)
pr.start()
cu.start()

文章到这里就结束了!希望大家能多多支持Python(系列)!六个月带大家学会Python,私聊我,可以问关于本文章的问题!以后每天都会发布新的文章,喜欢的点点关注!一个陪伴你学习Python的新青年!不管多忙都会更新下去,一起加油!

Editor:Lonelyroots

上一篇 下一篇

猜你喜欢

热点阅读