zoukankan      html  css  js  c++  java
  • 37-进程与线程(代码篇)

    进程对象及其他方法

    """
    一台计算机上面运行着很多进程,那么计算机是如何区分并管理这些进程服务端的呢?
    计算机会给每一个运行的进程分配一个PID号 
    如何查看
    	windows电脑 
    		进入cmd输入tasklist即可查看
    		tasklist |findstr PID查看具体的进程
    	mac电脑 
    		进入终端之后输入ps aux
    		ps aux|grep PID查看具体的进程 
    """
    from multiprocessing import Process, current_process
    current_process().pid  # 查看当前进程的进程号
    
    import os
    os.getpid()  # 查看当前进程进程号
    os.getppid()  # 查看当前进程的父进程进程号
    
    
    p.terminate()  # 杀死当前进程
    # 是告诉操作系统帮你去杀死当前进程 但是需要一定的时间 而代码的运行速度极快
    time.sleep(0.1)
    print(p.is_alive())  # 判断当前进程是否存活
    

    僵尸进程与孤儿进程(了解)

    # 僵尸进程
    """
    死了但是没有死透
    当你开设了子进程之后 该进程死后不会立刻释放占用的进程号
    因为我要让父进程能够查看到它开设的子进程的一些基本信息 占用的pid号 运行时间。。。
    所有的进程都会步入僵尸进程
    	父进程不死并且在无限制的创建子进程并且子进程也不结束
    	回收子进程占用的pid号
    		父进程等待子进程运行结束
    		父进程调用join方法
    """
    
    # 孤儿进程
    """
    子进程存活,父进程意外死亡
    操作系统会开设一个“儿童福利院”专门管理孤儿进程回收相关资源
    """
    

    守护进程

    在start开启进程上方,指定进程p为守护进程 p.daemon = True

    其一:守护进程会在主进程代码执行结束后就终止
    其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes are not allowed to have children
    注意:进程之间是互相独立的

    from multiprocessing import Process
    import time
    
    
    def task(name):
        print('%s总管正在活着'% name)
        time.sleep(3)
        print('%s总管正在死亡' % name)
    
    
    if __name__ == '__main__':
        p = Process(target=task,args=('egon',))
        # p = Process(target=task,kwargs={'name':'egon'})
        p.daemon = True  # 将进程p设置成守护进程  这一句一定要放在start方法上面才有效否则会直接报错
        p.start()
        print('皇帝jason寿终正寝')
    

    互斥锁

    多个进程操作同一份数据的时候,会出现数据错乱的问题

    针对上述问题,解决方式就是加锁处理:将并发变成串行,牺牲效率但是保证了数据的安全

    from multiprocessing import Process, Lock
    import json
    import time
    import random
    
    
    # 查票
    def search(i):
        # 文件操作读取票数
        with open('data','r',encoding='utf8') as f:
            dic = json.load(f)
        print('用户%s查询余票:%s'%(i, dic.get('ticket_num')))
        # 字典取值不要用[]的形式 推荐使用get  你写的代码打死都不能报错!!!
    
    
    # 买票  1.先查 2.再买
    def buy(i):
        # 先查票
        with open('data','r',encoding='utf8') as f:
            dic = json.load(f)
        # 模拟网络延迟
        time.sleep(random.randint(1,3))
        # 判断当前是否有票
        if dic.get('ticket_num') > 0:
            # 修改数据库 买票
            dic['ticket_num'] -= 1
            # 写入数据库
            with open('data','w',encoding='utf8') as f:
                json.dump(dic,f)
            print('用户%s买票成功'%i)
        else:
            print('用户%s买票失败'%i)
    
    
    # 整合上面两个函数
    def run(i, mutex):
        search(i)
        # 给买票环节加锁处理
        # 抢锁
        mutex.acquire()
    
        buy(i)
        # 释放锁
        mutex.release()
    
    
    if __name__ == '__main__':
        # 在主进程中生成一把锁 让所有的子进程抢 谁先抢到谁先买票
        mutex = Lock()
        for i in range(1,11):
            p = Process(target=run, args=(i, mutex))
            p.start()
    """
    扩展 行锁 表锁
    
    注意:
    	1.锁不要轻易的使用,容易造成死锁现象(我们写代码一般不会用到,都是内部封装好的)
    	2.锁只在处理数据的部分加来保证数据安全(只在争抢数据的环节加锁处理即可) 
    """
    

    进程间通信

    队列Queue模块

    """
    管道:subprocess 
    	stdin stdout stderr
    队列:管道+锁
    
    队列:先进先出
    堆栈:先进后出
    """
    from multiprocessing import Queue
    
    # 创建一个队列
    q = Queue(5)  # 括号内可以传数字 标示生成的队列最大可以同时存放的数据量
    
    # 往队列中存数据
    q.put(111)
    q.put(222)
    q.put(333)
    # print(q.full())  # 判断当前队列是否满了
    # print(q.empty())  # 判断当前队列是否空了
    q.put(444)
    q.put(555)
    # print(q.full())  # 判断当前队列是否满了
    
    # q.put(666)  # 当队列数据放满了之后 如果还有数据要放程序会阻塞 直到有位置让出来 不会报错
    
    """
    存取数据 存是为了更好的取
    千方百计的存、简单快捷的取
    
    同在一个屋檐下
    差距为何那么大
    """
    
    # 去队列中取数据
    v1 = q.get()
    v2 = q.get()
    v3 = q.get()
    v4 = q.get()
    v5 = q.get()
    # print(q.empty())
    # V6 = q.get_nowait()  # 没有数据直接报错queue.Empty
    # v6 = q.get(timeout=3)  # 没有数据之后原地等待三秒之后再报错  queue.Empty
    try:
        v6 = q.get(timeout=3)
        print(v6)
    except Exception as e:
        print('一滴都没有了!')
    
    # # v6 = q.get()  # 队列中如果已经没有数据的话 get方法会原地阻塞
    # print(v1, v2, v3, v4, v5, v6)
    
    """
    q.full()
    q.empty()
    q.get_nowait()
    在多进程的情况下是不精确
    """
    

    IPC机制

    from multiprocessing import Queue, Process
    
    """
    研究思路
        1.主进程跟子进程借助于队列通信
        2.子进程跟子进程借助于队列通信
    """
    def producer(q):
        q.put('我是23号技师 很高兴为您服务')
    
    
    def consumer(q):
        print(q.get())
    
    
    if __name__ == '__main__':
        q = Queue()
        p = Process(target=producer,args=(q,))
        p1 = Process(target=consumer,args=(q,))
        p.start()
        p1.start()
    

    生产者消费者模型

    """
    生产者:生产/制造东西的
    消费者:消费/处理东西的
    该模型除了上述两个之外还需要一个媒介
    	生活中的例子做包子的将包子做好后放在蒸笼(媒介)里面,买包子的取蒸笼里面拿
    	厨师做菜做完之后用盘子装着给你消费者端过去
    	生产者和消费者之间不是直接做交互的,而是借助于媒介做交互
    	
    生产者(做包子的) + 消息队列(蒸笼) + 消费者(吃包子的)
    """
    
    q = JoinableQueue()
    q.task_done()
    # 每当往队列中存入数据的时候,内部有一个计数器+1,每当调用q.task_done的时候,内部计数器-1
    q.join() # 在计数器为0的时候才会往后运行
    # join执行完毕,说明消费者消费完毕,就没有必要再存在了,所以应该把消费者设置成守护进程
    
    
    #JoinableQueue([maxsize]):这就像是一个Queue对象,但队列允许项目的使用者通知生成者项目已经被成功处理。
                    通知进程是使用共享的信号和条件变量来实现的。
    #参数介绍:
    '''
    maxsize是队列中允许最大项数,省略则无大小限制。    
    #方法介绍:
    JoinableQueue的实例p除了与Queue对象相同的方法之外还具有:
    q.task_done():使用者使用此方法发出信号,表示q.get()的返回项目已经被处理。如果调用此方法的次数大于从队列中删除项目的数量,
             将引发ValueError异常
    q.join():生产者调用此方法进行阻塞,直到队列中所有的项目均被处理。阻塞将持续到队列中的每个项目均调用q.task_done()方法为止
    '''
    

    https://www.cnblogs.com/zhubincheng/p/12764791.html#_label0

    线程理论

    致命三问

    • 什么是线程

      """
      进程:资源单位
      线程:执行单位
      
      将操作系统比喻成一个大的工厂
      那么进程就相当于工厂里面的车间
      而线程就是车间里面的流水线
      
      每一个进程肯定自带一个线程
      
      再次总结:
      	进程:资源单位(起一个进程仅仅只是在内存空间中开辟一块独立的空间)
      	线程:执行单位(真正被cpu执行的其实是进程里面的线程,线程指的就是代码的执行过程,执行代码中所需要使用到的资源都找所在的进程索要)
      	
      进程和线程都是虚拟单位,只是为了我们更加方便的描述问题
      """
      
    • 为何要有线程

      """
      开设进程
      	1.申请内存空间	耗资源
      	2.“拷贝代码”   耗资源
      开线程
      	一个进程内可以开设多个线程,在用一个进程内开设多个线程无需再次申请内存空间操作
      
      总结:
      	开设线程的开销要远远的小于进程的开销
      	同一个进程下的多个线程数据是共享的!!!
      """
      我们要开发一款文本编辑器
      	获取用户输入的功能
        实时展示到屏幕的功能
        自动保存到硬盘的功能
      针对上面这三个功能,开设进程还是线程合适???
      	开三个线程处理上面的三个功能更加的合理
      
  • 相关阅读:
    e621. Activating a Keystroke When Any Child Component Has Focus
    e587. Filling Basic Shapes
    e591. Drawing Simple Text
    e595. Drawing an Image
    e586. Drawing Simple Shapes
    e636. Listening to All Key Events Before Delivery to Focused Component
    在 PL/SQL 块的哪部分可以对初始变量赋予新值? (选择1项)
    Oracle数据库中,在SQL语句中连接字符串的方法是哪个?(选择1项)
    你判断下面语句,有什么作用?(单选)
    Oracle数据库表空间与数据文件的关系描述正确的是( )
  • 原文地址:https://www.cnblogs.com/zhubincheng/p/12764608.html
Copyright © 2011-2022 走看看