• 并发编程


    概念
        # 同步异步阻塞和非阻塞
            # 同步阻塞 : 调用一个函数需要等待这个函数的执行结果,并且在执行这个函数的过程中CPU不工作
                # inp = input('>>>')
            # 同步非阻塞 :调用一个函数需要等待这个函数的执行结果,在执行这个函数的过程中CPU工作
                # ret = eval('1+2+3-4')
            # 异步非阻塞 :调用一个函数不需要等待这个函数的执行结果,并且在执行这个函数的过程中CPU工作
                # start()
            # 异步阻塞 : 调用一个函数不需要等待这个函数的执行结果,并且在执行这个函数的过程中CPU不工作
                # 开启10个进程 异步的
                # 获取这个进程的返回值,并且能做到哪一个进程先结束,就先获取谁的返回值
        # 进程的三状态图
            # 就绪 -操作系统调度->运行 -遇到io操作-> 阻塞 -阻塞状态结束-> 就绪
            #                         -时间片到了-> 就绪
        # 进程的调度算法 : 短作业和长作业是有区别的,越长的作业被调度的没有短作业调度的积极
                         # 每一个io操作都会让你辛苦排来的队执行的CPU机会让给其他程序
            # 先来先服务
            # 短作业优先
            # 分时的概念
            # 多级反馈算法
        # 进程开启和关闭
            # 父进程 开启了 子进程
            # 父进程 要负责给 子进程 回收子进程结束之后的资源

    1.multiprocessing 多元的处理进程的模块

    import os
    from multiprocessing import Process
    
    print(os.getpid(), os.getppid())  #进程ID1828    父进程id 3852
    
    def func():
        print(os.getpid(),os.getppid())
        # pid process id           进程id
        # ppid parent process id   父进程id
    
    
    
    if __name__ == '__main__':
        # 只会在主进程中执行的所有的代码你写在name = main下
        print('main :',os.getpid(),os.getppid())
        p = Process(target=func)
        p.start()         #开启一个子进程
    能不能给子进程传递参数   
    #能  p = Process(target=func,args=('alex',84))
    
    # import os
    # from multiprocessing import Process
    #
    # def func(name,age):
    #     print(os.getpid(),os.getppid(),name,age)
    #
    # if __name__ == '__main__':
    #     # 只会在主进程中执行的所有的代码你写在name = main下
    #     print('main :',os.getpid(),os.getppid())
    #     p = Process(target=func,args=('alex',84))
    #     p.start()
    能不能获取子进程的返回值   # 不能
    # 能不能同时开启多个子进程  可以
    
    import os
    import time
    from multiprocessing import Process
    
    def func(name,age):
        print('%s start'%name)
        time.sleep(1)        #异步并发
        print(os.getpid(),os.getppid(),name,age)
    
    if __name__ == '__main__':
        # 只会在主进程中执行的所有的代码你写在name = main下
        print('main :',os.getpid(),os.getppid())
        arg_lst = [('alex',84),('太白', 40),('wusir', 48)]
        for arg in arg_lst:
            p = Process(target=func,args=arg)  #args接收的参数必须是元组或列表
            p.start()  # 异步非阻塞

    2.join的用法

    import os
    import time
    import random
    import  json
    
    from multiprocessing import Process
    
    
    
    def func(name,age):
        print('发送一封邮件给%s岁的%s'%(age,name))
        # time.sleep(1)
        time.sleep(random.random())  #随机休眠
        print('发送完毕')
    
    if __name__ =='__main__':
        arg_lst = [('大壮',40),('alex', 84), ('太白', 40), ('wusir', 48)]
        p_list = []
    
        for i in arg_lst:
            p = Process(target=func, args=i)
            p.start()
            p_list.append(i)
        for p in p_list:
            p.join()
            # p.join()# 阻塞:直到p这个子进程执行完毕才继续执行    这是同步阻塞
        print('打印完成')
    # 同步阻塞 异步非阻塞
        # 同步阻塞 join
        # 异步非阻塞 start
    多进程之间的数据是否隔离   隔离的
    
    from multiprocessing import Process
    n = 0
    def func():
        global n
        n += 1
    
    if __name__ == '__main__':
        p_l = []
        for i in range(100):
            p = Process(target=func)
            p.start()
            p_l.append(p)
        for p in p_l:p.join()
        print(n)

    同步异步阻塞非阻塞

     在了解其他概念之前,我们首先要了解进程的几个状态。在程序运行的过程中,由于被操作系统的调度算法控制,程序会进入几个状态:就绪,运行和阻塞。

      (1)就绪(Ready)状态

      当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行,这时的进程状态称为就绪状态。

      (2)执行/运行(Running)状态当进程已获得处理机,其程序正在处理机上执行,此时的进程状态称为执行状态。

      (3)阻塞(Blocked)状态正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。引起进程阻塞的事件可有多种,例如,等待I/O完成、申请缓冲区不能满足、等待信件(信号)等。

          

    process模块介绍

    process模块是一个创建进程的模块,借助这个模块,就可以完成进程的创建。

    Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,表示一个子进程中的任务(尚未启动)
    
    强调:
    1. 需要使用关键字的方式来指定参数
    2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号
    
    参数介绍:
    1 group参数未使用,值始终为None
    2 target表示调用对象,即子进程要执行的任务
    3 args表示调用对象的位置参数元组,args=(1,2,'egon',)
    4 kwargs表示调用对象的字典,kwargs={'name':'egon','age':18}
    5 name为子进程的名称
    1 p.start():启动进程,并调用该子进程中的p.run() 
    2 p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法  
    3 p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁
    4 p.is_alive():如果p仍然运行,返回True
    5 p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程  
    1 p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置
    2 p.name:进程的名称
    3 p.pid:进程的pid
    4 p.exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可)
    5 p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功(了解即可)
    在windoes使用时要注意的事项
    
    在Windows操作系统中由于没有fork(linux操作系统中创建进程的机制),在创建子进程的时候会自动 import 启动它的这个文件,而在 import 的时候又执行了整个文件。因此如果将process()直接写在文件中就会无限递归创建子进程报错。所以必须把创建子进程的部分使用if __name__ ==‘__main__’ 判断保护起来,import 的时候  ,就不会递归运行了。

    守护进程

    会随着主进程的结束而结束。

    主进程创建守护进程

      其一:守护进程会在主进程代码执行结束后就终止

      其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes are not allowed to have children

    注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止

    1.守护进程的启动

    import os
    import time
    from multiprocessing import Process
    
    class Myprocess(Process):
        def __init__(self,person):
            super().__init__()
            self.person = person
        def run(self):
            print(os.getpid(),self.name)
            print('%s正在和女主播聊天' %self.person)
    
    
    p=Myprocess('哪吒')
    p.daemon=True #一定要在p.start()前设置,设置p为守护进程,禁止p创建子进程,并且父进程代码执行结束,p即终止运行
    p.start()
    time.sleep(10) # 在sleep时查看进程id对应的进程ps -ef|grep id
    print('')

    2.主进程代码执行结束,守护进程立即结束

    from multiprocessing import Process
    
    def foo():
        print(123)
        time.sleep(1)
        print("end123")
    
    def bar():
        print(456)
        time.sleep(3)
        print("end456")
    
    
    p1=Process(target=foo)
    p2=Process(target=bar)
    
    p1.daemon=True
    p1.start()
    p2.start()
    time.sleep(0.1)
    print("main-------")#打印该行则主进程代码结束,则守护进程p1应该被终止.#可能会有p1任务执行的打印信息123,因为主进程打印main----时,p1也执行了,但是随即被终止.

    3.Process类的其它方法

    from multiprocessing import Process
    import os
    import time
    
    class Myprocess(Process):
        def __init__(self,a,b,c):
            self.a = a
            self.b = b
            self.c = c
            super().__init__()
    
    
        def run(self):
            time.sleep(1)
            print(os.getpid(),os.getppid(),self.a,self.b,self.c)
    
    if __name__ == '__main__':
        p = Myprocess(1,2,3)
        p.start()
        print(p.pid,p.ident)  #查看子进程ID
        print(p.name) #查看进程名字
        print(p.is_alive()) #查看进程是否存在
        p.terminate() #强制杀死进程
        time.sleep(1)
        print(p.is_alive())
    守护进程   要求守护进程p1必须在p2进程执行结束之后才结束
    from multiprocessing import  Process
    
    import time
    import os
    
    # 要求守护进程p1必须在p2进程执行结束之后才结束
    def son1():
        while True:
            print('<<<in son1')
            time.sleep(1)
    
    def son2():
        for i in range(10):
            print('in son2')
            time.sleep(1)
    
    if __name__ == '__main__':
        p = Process(target=son1)
        p.daemon = True
        p.start()
        p2 = Process(target=son2)
        p2.start()
        time.sleep(3)
        print('in _main_')
        p2.join()

    守护进程:锁

    抢票的例子  一个人抢到了.另外的人就不能够抢了
    
    import os
    import json,time
    from multiprocessing import Process,Lock
    
    
    def search(i):
        with open('ticker',mode='r',encoding='utf-8') as f:
            ticker = json.load(f)
            print('%s:当前还剩于%s张票'%(i,ticker['count']))
    
    
    
    def buy_ticker(i):
        with open('ticker',mode='r',encoding='utf-8') as f:
            ticker = json.load(f)
            if ticker['count'] > 0:
                ticker['count'] -= 1
                print('%s买到票了'%(i))
            time.sleep(0.1)
        with open('ticker',mode='w',encoding='utf-8') as f:
            json.dump(ticker,f)
    
    
    def get_ticker(i,lock):
        search(i)
    
        # lock.cquire()  #拿钥匙
        # buy_ticker(i)
        # lock.release()   #还钥匙
    
        with lock:   #
            buy_ticker(i)
    
    
    
    if __name__ == '__main__':
        lock = Lock()
    
        for i in range(10):
            p = Process(target=get_ticker,args=(i,lock))
            p.start()
    队列------完善的生产消费者模型  *****
     # 把原本获取数据处理数据的完整过程进行了 解耦
    # 把生产数据和消费数据分开,根据生产和消费的效率不同,来规划生产者和消费者的个数,
    # 让程序的执行效率达到平衡
    # 如果你写了一个程序所有的功能代码都放在一起,不分函数不分类也不分文件
    # 紧耦合的程序

    # 拆分的很清楚的程序
    # 松耦合的程序

    # 进程的生产者消费者模型(默写)
    # 多个进程访问网页
    # 一个进程负责把网页源码写到文件里
    # 消费者如何结束
    # 哪些部分是生产者消费者模型比较重要的结构



    import time
    import random
    from multiprocessing import Queue,Process
    
    
    def consumer(q,name): # 消费者:通常取到数据之后还要进行某些操作
        while True:
            food = q.get()
            if food:
                print('%s吃了%s'%(name,food))
            else:break
    
    def producer(q,name,food): # 生产者:通常在放数据之前需要先通过某些代码来获取数据
        for i in range(10):
            foodi = '%s%s'%(food,i)
            print('%s生产了%s'%(name,foodi))
            time.sleep(random.random())
            q.put(foodi)
    
    if __name__ == '__main__':
        q = Queue()
        c1 = Process(target=consumer,args=(q,'alex'))
        c2 = Process(target=consumer,args=(q,'alex'))
        p1 = Process(target=producer,args=(q,'大壮','泔水'))
        p2 = Process(target=producer,args=(q,'b哥','香蕉'))
        c1.start()
        c2.start()
        p1.start()
        p2.start()
        p1.join()
        p2.join()
        q.put(None)  #有多少个消费者.就需要有多少个put(none)
        q.put(None)
    同步阻塞
        # 调用函数必须等待结果cpu没工作 input sleep recv accept connect get
    # 同步非阻塞
        # 调用函数必须等待结果cpu工作 - 调用了一个高计算的函数 strip eval('1+2+3') sum max min sorted
    # 异步阻塞
        # 调用函数不需要立即获取结果,而是继续做其他的事情,在获取结果的时候不知道先获取谁的,但是总之需要等(阻塞)
    # 异步非阻塞
        #  调用函数不需要立即获取结果,也不需要等 start() terminate()
    异步阻塞
    
    
    import requests
    from multiprocessing import Process,Queue
    url_dic = {
        'cnblogs':'https://www.cnblogs.com/Eva-J/articles/8253549.html',
        'douban':'https://www.douban.com/doulist/1596699/',
        'baidu':'https://www.baidu.com',
        'gitee':'https://gitee.com/old_boy_python_stack__22/teaching_plan/issues/IXSRZ',
    
    }
    
    def producer(name,url,q):
        ret = requests.get(url)
        q.put((name,ret.text))
    
    def consumer(q):
        while True:
            tup = q.get()
            if tup is None:break
            with open('%s.html'%tup[0],encoding='utf-8',mode='w') as f:
                f.write(tup[1])
    
    if __name__ == '__main__':
        q = Queue()
        pl = []
        for key in url_dic:
            p = Process(target=producer,args=(key,url_dic[key],q))
            p.start()
            pl.append(p)
        Process(target=consumer,args=(q,)).start()
        for p in pl:p.join()
        q.put(None)

    数据共享  Manager 

    # _*_ coding : UTF-8 _*_
    from multiprocessing import Process,Manager,Lock
    
    def change_dic(dic,lock):
        with lock:   #����  �а�ȫ����
            dic['count'] -= 1
    
    if __name__ == '__main__':
        # m = Manager()    #�������ݹ���
        with Manager() as m:
            lock = Lock()
            dic = m.dict({'count': 100})
            # dic = {'count': 100}
            p_l = []
            for i in  range(100):
                p = Process(target=change_dic,args=(dic,lock))
                p.start()
                p_l.append(p)
            for p in p_l : p.join()
            print(dic)

     线程    threading模块开启线程

    # 线程
    # 概念
    # 数据共享,效率高开销小,可以被多个cpu调度(是CPU调度的最小单位),数据不安全,由操作系统负责调度
    # 在cpython解释器下 :GIL锁(全局解释器锁) 导致了同一个进程中的多个线程不能利用多核
    # 代码
    # threading
    # 对象 = 实例化的结果 : 指定target args
    # start
    # join
    # ident
    # current_thread 能够帮助你获取当前这句函数所在的线程的线程对象
    # enumerate 导入之后会和内置函数enumerate重名,需要做特殊的处理
    # from threading import enumerate as en
    # import threading
    # threading.enumerate()
    # active_count 查看存活的线程个数(包括主线程)

    threading模块 

    from threading import Thread,current_thread,enumerate,active_count #线程
    
    current_thread() 获取当前所在的线程的对象
    enumerate 列表 存储了所有活着的线程对象,包括主线程
    active_count 数字 存储了所有活着的线程个数
    import os
    import time
    from threading import Thread,current_thread,enumerate,active_count    #线程
    
    def func(i):
        print('start%s'%i,current_thread().ident)    #拿到所有线程的id。current_thread().是所有线程。ident是ID
        time.sleep(1)
        print('end%s'%i)
    if __name__ == '__main__':
        tl = []
        for i in range(10):
            t = Thread(target=func,args=(i,))
            t.start()
            print(t.ident,os.getpid())
            tl.append(t)
        print(enumerate(),active_count())   #共11个线程。10个加一个主线程   active_count 是记录所有活着的线程个数
        for t in tl:t.join()
        print('所有的线程都执行完了')
    
    
    
    # current_thread() 获取当前所在的线程的对象 current_thread().ident通过ident可以获取线程id
    # 线程是不能从外部   terminate   terminate是关闭
    # 所有的子线程只能是自己执行完代码之后就关闭
    # enumerate 列表 存储了所有活着的线程对象,包括主线程
    # active_count 数字 存储了所有活着的线程个数
    # 面向对象的方式起线程
    
    
    from threading import Thread
    class MyThread(Thread):
        def __init__(self,a,b):
            self.a = a
            self.b = b
            super().__init__()
    
        def run(self):
            print(self.ident)
    
    t = MyThread(1,2)
    t.start()  # 开启线程 才在线程中执行run方法
    print(t.ident)
    # 线程之间的数据的共享
    
    
    from threading import Thread
    n = 100
    
    def func():
        global n
        n -= 1
    
    t_l = []
    for i in range(100):
        t = Thread(target=func)
        t.start()
        t_l.append(t)
    for t in t_l:
        t.join()
    print(n)
    守护线程
    # 主线程会等待子线程结束之后才结束
    # 为什么? # 主线程结束进程就会结束
    # 守护线程随着主线程的结束而结束
    # 守护线程会在主线程的代码结束之后继续守护其他子线程么? 会的

    # 守护进程 会随着主进程的代码结束而结束
    # 如果主进程代码结束之后还有其他子进程在运行,守护进程不守护
    # 守护线程 随着主线程的结束而结束
    # 如果主线程代码结束之后还有其他子线程在运行,守护线程也守护

    # 为什么?
    # 守护进程和守护线程的结束原理不同
    # 守护进程需要主进程来回收资源
    # 守护线程是随着进程的结束才结束的
    # 其他子线程-->主线程结束-->主进程结束-->整个进程中所有的资源都被回收-->守护线程也会被回收

    # 进程是资源分配单位
    # 子进程都需要它的父进程来回收资源
    # 线程是进程中的资源
    # 所有的线程都会随着进程的结束而被回收的



  • 相关阅读:
    jQuery 选择器:元素选择器、#id 选择器、.class 选择器
    jQuery 语法:文档就绪事件
    jQuery 安装:多种方法在网页中添加 jQuery
    jQuery 简介:什么事jQuery?为什么要学jQuery?
    SQL 快速参考:SQL语句语法
    SQL FORMAT() 函数:对字段的显示进行格式化
    Mybatis-Plus逻辑删除
    Mybatis-Plus中的ActiveRecord
    Mybatis-Plus使用Oracle的序列
    SpringBoot整合Mybatis-Plus
  • 原文地址:https://www.cnblogs.com/zengluo/p/12914987.html
Copyright © 2020-2023  润新知