• 进程间通信与线程


    进程间通信与线程

    一、进程间通过队列通信

    """
    队列:先进先出
    堆栈:先进后出
    """
    from multiprocessing import Queue
    
    
    q = Queue(5)  # 括号内可以传参数 表示的是这个队列的最大存储数
    # 往队列中添加数据
    q.put(1)
    q.put(2)
    # print(q.full())  # 判断队列是否满了
    q.put(3)
    q.put(4)
    q.put(5)
    # print(q.full())
    # q.put(6)  # 当队列满了之后 再放入数据 不会报错 会原地等待 直到队列中有数据被取走(阻塞态)
    
    print(q.get())
    print(q.get())
    print(q.get())
    print(q.empty())  # 判断队列中的数据是否取完
    print(q.get())
    print(q.get())
    print(q.empty())
    # print(q.get_nowait())  # 取值 没有值不等待直接报错
    # print(q.get())  # 当队列中的数据被取完之后 再次获取 程序会阻塞 直到有人往队列中放入值
    """
    full
    get_nowait
    empty
    都不适用于多进程的情况
    """
    
    q = Queue(5)限定这个队列中最多存放5个值,不写则为默认值(这个值很大)
    q.full()用于查看这个队列是否已满
    q.empty()用于查看这个队列是否为空
    q.put()用于往队列里面放值,如果队列已满,则原地等待队列中的值被取走(阻塞态)
    q.get()用于从队列里面取值,如果队列已空,则原地等待有人向队列中放值(阻塞态)
    q.get_nowait()与q.get()用途一致,区别在于,当队列里面没有值的时候,会直接报错
    

    二、进程间通信IPC(inter process communication)

    from multiprocessing import Process,Queue
    
    def producer(q):
        q.put('hello GF~')
    
    def consumer(q):
        print(q.get())
    
    if __name__ == '__main__':
        q = Queue()
        p = Process(target=producer,args=(q,))
        c = Process(target=consumer, args=(q,))
        p.start()
        c.start()
    
    
    """
    子进程放数据 主进程获取数据
    两个子进程相互放 取数据
    """
    

    三、生产者消费者模型

    """
    生产者:生产/制造数据的
    消费者:消费/处理数据的
    例子:做包子的,买包子的
            1.做包子远比买包子的多
            2.做包子的远比包子的少
            供需不平衡的问题
    """
    from multiprocessing import Process,Queue,JoinableQueue
    import random
    import time
    
    
    def producer(name,food,q):
        for i in range(10):
            data = '%s生产了%s%s'%(name,food,i)
            time.sleep(random.random())
            q.put(data)
            print(data)
    
    def consumer(name,q):
        while True:
            data = q.get()
            if data == None:break
            print('%s吃了%s'%(name,data))
            time.sleep(random.random())
            q.task_done()  # 告诉队列你已经从队列中取出了一个数据 并且处理完毕了
    
    
    
    if __name__ == '__main__':
        q = JoinableQueue()
        
        p = Process(target=producer,args=('大厨egon','馒头',q))
        p1 = Process(target=producer,args=('跟班tank','生蚝',q))
        c = Process(target=consumer,args=('许兆龙',q))
        c1 = Process(target=consumer,args=('吃货jerry',q))
        p.start()
        p1.start()
        c.daemon = True
        c1.daemon = True
        c.start()
        c1.start()
        p.join()
        p1.join()
    
        q.join()  # 等待队列中数据全部取出
    

    四、线程

    1、什么是线程

    • 进程线程其实都是虚拟单位,都是用来帮助我们形象的描述某种事物

    • 进程:资源单位

    • 线程:执行单位

      将内存比喻成工厂

      那么进程就相当于是工厂里面的车间

      而线程就相当于是车间里面的流水线

    PS:每个进程都自带一个线程,线程才是真正的执行单位,进程只是在线程运行过程中提供代码运行所需要的资源

    2、为什么要有线程

    • 开进程

      申请内存空间,消耗资源

      拷贝代码,消耗资源

    • 开线程

      一个进程内可以开多个线程,并且线程与线程之间数据时共享的

    PS:开启线程的开销要远远小于开启进程的开销

    五、创建线程的两种方式

    # 方式一
    from threading import Thread
    import time
    
    
    def task(name):
        print(f'{name} is running')
        time.sleep(1)
        print(f'{name} is over')
    
    
    t = Thread(target=task, args=('egon',))
    t.start()
    print('主')
    '''
    开线程不需要在__main__代码块中执行,但是习惯性还是写在__main__代码块内
    由于开启线程的开销要远远低于进程,所以会出现egon is running这句话在“主”之前打印
    同样的,主线程的代码执行完毕后,也要等待子线程的代码执行完毕才能结束运行
    因为主线程的结束意味着主进程的结束,而主进程一旦结束,主进程所占用的内存空间就会被操作系统回收,而子线程是在主进程中创建的,所以主线程在子线程之前结束,会导致子线程被强行终止。
    '''
    
    # 方式二
    from threading import Thread
    import time
    
    
    class MyThread(Thread):
        def __init__(self, name):
            super().__init__()
            self.name = name
    
        def run(self):
            print(f'{self.name} is running')
            time.sleep(1)
            print(f'{self.name} is over')
    
    
    p = MyThread('egon')
    p.start()
    print('主')
    '''
    与进程的创建类似,创建一个类继承Thread类,覆盖__init__方法,run()方法。
    '''
    

    六、线程对象及其他方法

    from threading import Thread, current_thread, active_count
    import time
    import os
    
    
    def task(name, i):
        print(f'{name} is running')
        print('子线程名', current_thread().name)
        print('子线程所处进程号', os.getpid())
        time.sleep(i)
        print(f'{name} is over')
    
    
    if __name__ == '__main__':
        t = Thread(target=task, args=('egon', 2))
        t1 = Thread(target=task, args=('jason', 1))
        t.start()
        t1.start()
        t1.join()
        print('当前正在活跃的线程数', active_count())
        print('主')
        print('主线程号', current_thread().name)
        print('主线程所处进程号', os.getpid())
    '''
    current_thread()表示当前线程
    current_thread().name查看当前线程名
    active_count()统计当前正在活跃的线程数
    '''
    

    七、守护线程

    from threading import Thread, current_thread
    import time
    
    
    def task(i):
        print(current_thread().name)
        time.sleep(i)
        print('GG')
    
    
    if __name__ == '__main__':
        # for i in range(3):
        #     t = Thread(target=task, args=(i,))
        #     t.start()
        t = Thread(target=task, args=('egon',))
        t.daemon = True  # 将该线程设置为主线程的守护线程,一旦主线程运行结束,子线程也跟着结束
        t.start()
        print('主')
    # Thread-1
    # 主
    '''
    ***GG不会打印***
    主线程的结束也就意味着进程的结束
    主线程必须等待其他非守护线程的结束才能结束
    (意味子线程在运行的时候需要使用进程中的资源,而主线程一旦结束了资源也就销毁了)
    '''
    

    八、线程间通信

    from threading import Thread
    
    money = 100
    
    
    def task():
        global money
        money = 666
    
    
    t = Thread(target=task)
    t.start()
    t.join()
    print(money)
    '''
    子线程修改了主线程的值,线程间的数据是共享的
    '''
    

    九、互斥锁

    from threading import Thread, Lock
    import time
    
    n = 100
    
    
    def task(mutex):
        global n
        mutex.acquire()
        temp = n
        time.sleep(0.1)  # 模拟网络延迟
        n = temp - 1
        mutex.release()
    
    
    t_list = []
    mutex = Lock()
    for i in range(100):
        t = Thread(target=task, args=(mutex,))
        t.start()
        t_list.append(t)
    for t in t_list:
        t.join()
    print(n)
    '''
    多个线程同时操作同一个数据,则会出现数据错乱的现象
    想到加锁,与进程中的互斥锁类似
    '''
    

    十、一道小题目

    from threading import Thread
    import time
    
    
    def foo():
        print(123)
        time.sleep(1)
        print('end123')
    
    
    def bar():
        print(456)
        time.sleep(2)
        print('end456')
    
    
    if __name__ == '__main__':
        t1 = Thread(target=foo)
        t2 = Thread(target=bar)
        t1.daemon = True
        t1.start()
        t2.start()
        print('main')
    '''
    打印结果:
    123
    456
    main
    end123
    end456
    
    虽然将t1设为为守护线程了,但主线程代码运行结束以后并不会立即结束,而是会等待所有非守护线程结束之后才结束,在本例中,t2即为非守护线程,在它结束之前t1线程就已经结束了。如果t2线程结束之后,t1线程还未结束,那么end123这句话就不会打印。
    '''
    
  • 相关阅读:
    Windows如何快速远程到另一台Windows并管理多个远程服务器
    基于视觉反馈的步进电机X-Y平台控制
    相机位姿估计3:根据两幅图像的位姿估计结果求某点的世界坐标
    相机位姿估计2:[应用]实时位姿估计与三维重建相机姿态
    相机位姿估计1_1:OpenCV:solvePnP二次封装与性能测试
    求空间内两条直线的最近距离以及最近点的坐标(C++)
    相机位姿估计1:根据四个特征点估计相机姿态
    相机位姿估计0:基本原理之如何解PNP问题
    记2016年中国移动广西公司面试(计算机类)
    子坐标系C在父坐标系W中的旋转问题
  • 原文地址:https://www.cnblogs.com/DcentMan/p/11380558.html
Copyright © 2020-2023  润新知