• 并发编程——进程线程


    并发编程

    子进程回收资源的两种方式:

    1. join让主进程等待子进程结束,并回收子进程资源,主进程再结束并回收资源。
    2. 主进程‘正常结束’,子进程与主进程一并被回收资源。

    守护进程:

    主进程结束时,子进程也必须结束,并回收。

    进程间数据是隔离的

    进程互斥锁:

    互斥锁是一把锁,用来保证数据读写安全的。

    抢票列子

    from multiprocessing import Process
    from multiprocessing import Lock  # ---》 进程互斥锁
    import random
    import time
    import json
    # 抢票例子:
    # 1.查看余票
    def search(name):
        # 1.读取data.json文件中的数据
        with open('data.json', 'r', encoding='utf-8') as f:
            data_dic = json.load(f)
            print(f'用户【{name}】查看余票,余票还剩: {data_dic.get("number")}!')
    
    
    # 2.若有余票,购买成功,票数会减少
    def buy(name):  # buy()
    
        # 网络延时
        with open('data.json', 'r', encoding='utf-8') as f:
            data_dic = json.load(f)
    
        # 进入这一步证明最先抢到票
        if data_dic.get('number') > 0:
            data_dic['number'] -= 1
            time.sleep(random.randint(1, 3))
            with open('data.json', 'w', encoding='utf-8') as f:
                 json.dump(data_dic, f)
            print(f'用户【{name}】, 抢票成功!')
    
        else:
            print(f'用户【{name}】, 抢票失败!')
    
    def run(name, lock):
        # 1.假设1000个用户过来都可以立马查看余票
        search(name)
    
        lock.acquire()  # 加锁
        buy(name)
        lock.release()  # 释放锁
    
    if __name__ == '__main__':
        lock = Lock()
        # 开启多进程: 实现并发
        for line in range(10):
            p_obj = Process(target=run, args=(f'jason{line}', lock))
            p_obj.start()
    

    队列:

    先进先出

    --->[3,2,1]---->[1,2,3]
    

    先存放的数据,就先取出来.

    应用:让进程之间数据进行交互.

    IPC机制(进程间实现通信)

    面试会问:什么是IPC机制

    from multiprocessing import Process
    from multiprocessing import JoinableQueue
    import time
    
    def task1(q):
        x = 100
        q.put(x)
        print('添加数据')
    
        time.sleep(3)
        print(q.get())
    
    def task2(q):
        # 想要在task2中获取task1的x
        res = q.get()
        print(f'获取的数据是{res}')
        q.put(9527)
    
    if __name__ == '__main__':
        # 产生队列
        q = JoinableQueue(10)
    
        # 产生两个不同的子进程
        p1 = Process(target=task1, args=(q, ))
        p2 = Process(target=task2, args=(q, ))
    
        p1.start()
        p2.start()
    

    生产者与消费者

    生产者:生产数据的

    消费者:使用数据的

    生产油条的人总比吃油条的人少—>生产数据跟不上,使用数据的人—>供需不平衡

    吃油条的人比生产的油条要少—>使用数据的速度跟不上生产数据的 速度

    通过队列来实现

    from multiprocessing import JoinableQueue
    from multiprocessing import Process
    import time
    
    # 生产者: 生产数据 ---》 队列
    def producer(name, food, q):
        msg = f'{name} 生产了 {food} 食物'
        # 生产一个食物,添加到队列中
        q.put(food)
        print(msg)
    
    # 消费者: 使用数据 《---  列队
    def customer(name, q):
        while True:
            try:
                time.sleep(0.5)
                # 若报错,则跳出循环
                food = q.get_nowait()
                msg = f'{name} 吃了 {food} 食物!'
                print(msg)
            except Exception:
                break
                
    if __name__ == '__main__':
        q = JoinableQueue()
    
        # 创建两个生产者
        for line in range(10):
            p1 = Process(target=producer, args=('tank1', f'Pig饲料{line}', q))
            p1.start()
    
        # 创建两个消费者
        c1 = Process(target=customer, args=('jason', q))
        c2 = Process(target=customer, args=('sean', q))
        c1.start()
        c2.start()
    

    线程:

    什么是线程?

    进程:资源单位

    线程:执行单位

    线程与进程都是虚拟的概念,为了更好表达某种事物.

    注意:开启一个进程,一定会自带一个线程,线程才是真正的执行者.

    为什么使用线程?

    节省资源的占用.

    开启进程:

    1. 会产生一个内存空间,申请一块资源.
    2. 会自带一个主线程
    3. 开启子进程的速度要比开启子进程的速度慢

    开启线程:

    1. 一个进程内可以开启的多个线程,从进程的内存中申请执行单位.
    2. 节省资源

    开启三个进程:

    1. 占用三份内存资源

    开启三个线程:

    1. 从一个内存资源中,申请三个小时执行单位

    IO密集型用:多线程

    1. IO(时间由用户定):

      阻塞:切换+保存状态

    计算密集型用:多进程

    1. 计算(时间由操作系统定)

      计算时间很长—>切换+保存状态

    注意:进程与进程之间的数据是隔离的,线程与线程之间的 数据是共享的

    怎么使用线程?
    from threading import Thread
    import time
    number = 1000
    
    启动线程的方式一:
    任务1:
    def task():
        global number
        number = 100
        print('start...')
        time.sleep(1)
        print('end...')
    
    if __name__ == '__main__':
        # 开启一个子线程
        t = Thread(target=task)
        t.start()
        # t.join()
        print('主进程(主线程)...')
        print(number)
    
    启动线程的方式二:
    class MyThread(Thread):
        def run(self):
            print('start...')
            time.sleep(1)
            print('end...')
    
    if __name__ == '__main__':
        # 开启一个子线程
        t = MyThread()
        t.start()
        # t.join()
        print('主进程(主线程)...')
    
    from threading import current_thread
    number = 1000
    def task():
        global number
        number = 100
        print(f'start...{current_thread().name}')
        time.sleep(3)
        print(f'end...{current_thread().name}')
    
    if __name__ == '__main__':
        # 开启一个子线程
        for line in range(10):
            t = Thread(target=task)
            # 加上守护线程: 主进程结束,代表主线程也结束,子线程有可能未被回收。
            t.daemon = True
            t.start()
    
        # t.join()
        print(f'主进程(主线程)...{current_thread().name}')
        print(number)
    

    线程池

    线程池是用来限制 创建的线程数

    线程池演示链接

    我把月亮戳到天上 天就是我的 我把脚踩入地里 地就是我的 我亲吻你 你就是我的
  • 相关阅读:
    [ios] 分辨率
    [bat] 图片裁剪工具ImageMagick
    [ASP.NET] 调用32位ORACLE错误
    [Linux] 开启ESX的SSH
    [Linux] 关机和重启命令
    [.net] 关于CS0016: Could not write to output file ‘c:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files… ‘Access is denied.’ 的解决办法
    [linux] XEN里面的虚拟机centos无法使用date s设置时间
    字符串替换,string的强大
    C语言学习笔记(1)
    C语言学习笔记(8)
  • 原文地址:https://www.cnblogs.com/zhulipeng-1998/p/12863899.html
Copyright © 2020-2023  润新知