美文网首页Python好文有约简友广场
Python(三十一)并发通信

Python(三十一)并发通信

作者: Lonelyroots | 来源:发表于2021-12-03 12:37 被阅读0次

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

    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

    相关文章

      网友评论

        本文标题:Python(三十一)并发通信

        本文链接:https://www.haomeiwen.com/subject/wqwyxrtx.html