python中的多任务

多任务

多任务
    
    什么是任务
        一个电脑运行这的软件
    什么是多任务
        电脑同时运行着的多个软件
    多任务原理
        时间片的轮转
    并行与并发
        并发:假的多任务,多个任务共用一个核
        并行:正的多任务,一个核处理一个程序
    生理过程(从生到死)
        创建 -> 就绪 -> 运行 -> 阻塞 -> 死亡
    线程和进程的创建一定要在主函数中,且主任务和子任务一起往下执行,遇到join()方法,主任务会等子任务执行完在结束
View Code

线程

线程
        特点
            查看正在运行的线程列表
            threading.enumerate()
            只要程序已启动,Python解释器就会自动创建一个主线程
            主线程等待其他线程结束后在结束
            线程target指向的函数执行完毕,线程就结束了
            子线程是调用start()之后开启的
            多个线程共享全局变量 
            
                
        创建
            通过继承的方式创建线程
                特点:写法复杂,使用简单,可以使用对象的特性(封装、继承、多态)
                       业务逻辑比较复杂时使用
            方式一
                import threading
                p = threading.THread(target=函数名,args=(1,))
                p.start()
                p.join()
                
            方式二       
                import threading
                class MyThread(threading.Thread):
                    def run():
                        子线程要做的事情
                t = MyThread()
                t.start()
                t.join()
        互斥锁
            -->科学家吃面(筷子和碗)
            1.什么是资源竞争?
                多个线程争抢做同一件事
            2.资源竞争会带来什么问题?
                多线程共享同一个资源的时候,当操作这个资源(变量)足够多的次数时,可能会出现问题 eg:1000000次的累加
            3.如何解决资源竞争的问题?
                互斥锁
            4.什么是互斥锁?
                确保了某段关键代码只能由一个线程从头到尾完整地执行
            5.如何使用互斥锁?
                1.创建锁对象
                    mutex = threading.Lock()
                2.获取锁
                    mutex.acquire()
                3.释放锁
                    mutex.release()
            6.原则:
                存在资源竞争的代码
                加锁的代码越少越少
            7.死锁
                什么是死锁?
                    线程1等待线程2释放锁,线程2等待线程1释放锁
                如何解决死锁?
                    1.设计写代码的时候就避免
                    2.设置超时时间
                    3.银行家算法
View Code

进程

进程
        1.程序:
            就是程序员写的代码,没有运行起来的代码
        2.进程
            运行起来的程序,代码+计算机资源
            进程是实现多任务的第二种方式
        3.程序运行起来之后,Python解释器会给程序创建一个进程,叫做主进程
        
        特点
            1.查看进程
                windows: 任务管理器
                linux:ps -aux
                   杀死进程  kill -9 PID
                   top  htop 相当于windows中的任务管理器
            2.进程的写实拷贝
                写(修改)的时候拷贝一份
                进程不共享全局变量
                通过args给进程传递数据
            3.获取进程id和父进程的id
                os.getpid()
                os.getppid()
            4.主进程等待子进程结束后再结束(主进程替子进程收尸),进程的运行顺便不确定
            
        创建
            方式一
                import multiprocessing
                p = multiprocessing.Process(target=函数名,args=(1,))
                p.start()
                p.join()
            方式二
                import multiprocessing
                class MyProcess(multiprocessing.Process):
                    def run():
                        print("子线程要做的事情")
                p = MyProcess()
                p.start()
                p.join()
        进程间通信(传递数据)
            默认情况下,进程之间不能互相访问数据
            队列(Queue)
                常用的方法 
                    get()/put()/full()
                每个进程都可以往这个队列中写数据,都可以从这个队列中读取数据
            编码步骤:
                创建队列对象
                给队列中放数据
                从队列中取数据
        进程池(Pool)
            
            什么是进程池?
                一次性在进程池中创建多个进程
            进程的作用?
                减少了销毁线程的次数,从而提高效率
            如何使用进程池?
                创建进程池对象
                调用方法完成任务
        
            from multiprocessing import Pool
            import os, time, random
            def worker(msg):
                t_start = time.time()
                print("%s开始执行,进程号为%d" % (msg, os.getpid()))
                # random.random()随机生成0~1之间的浮点数
                time.sleep(random.random() * 2)
                t_stop = time.time()
                print(msg, "执行完毕,耗时%0.2f" % (t_stop - t_start))


            def main():
                po = Pool(3)  # 定义一个进程池,最大进程数3
                for i in range(0, 10):
                    # Pool().apply_async(要调用的目标,(传递给目标的参数元祖,))
                    # 每次循环将会用空闲出来的子进程去调用目标
                    po.apply_async(worker, (i,))

                print("----start----")
                po.close()  # 关闭进程池,关闭后po不再接收新的请求
                time.sleep(1)
                # po.join()  # 等待po中所有子进程执行完成,必须放在close语句之后
                print("-----end-----")


            if __name__ == '__main__':
                main()
View Code

协程

协程
        什么是可迭代对象
            一个普通的对象实现了iter内置函数
        什么是迭代器
            一个普通的对象实现了iter和next内置函数
        迭代器的特点
            保存的是生成数据的方式,而不直接存储数据
            好处:节省系统空间
        什么是生成器
            它是一个特殊的迭代器
        yield
            一个普通的函数里面写了yield的话,他就是一个生成器模板
            执行函数遇到yield会阻塞
            调用next()或者send()会解阻塞
            send()可以用来传递参数
            eg:
                def func(all_num):
                a, b = 0, 1
                count_num = 0
                while True:
                    if count_num < all_num:
                        result = yield a  # 如果一个函数中有yield,则说明这是特殊函数,叫生成器的模板
                        print(">>>>ret>>>>", result)
                        a, b = b, a + b
                        count_num += 1
                    else:
                        raise StopIteration

            f = func(10)
            ret = next(f)
            print(ret)
            ret = f.send("hahaha")   # 将这个结果传递给 result = yield a 让result来保存"hahaha"
            ret1 = next(f)
            print(ret1)      # 结果为None传递一次send后,后面的数据都需要send来传输,否则结果为None
            ret2 = f.send("ok")
            
        利用yield做协程
            写多个函数,每个函数中都写yield,函数执行时遇到yield就会阻塞
            然后交替着调用不同任务的next()方法,这样就用协程实现了多任务        
            原理:
                利用线程的空闲时间去执行其他的任务
            特点:
                协程依赖于线程,线程依赖进程
                从系统开销讲,进程>线程>协程
                
        创建协程
            yield  next()  send()
            
            import gevent
            import time
            from gevent import monkey

            monkey.patch_all()

            def func1(num):
                for i in range(num):
                    print(gevent.getcurrent(), i)
                    time.sleep(0.5)

            def func2(num):
                for i in range(num):
                    print(gevent.getcurrent(), i)
                    time.sleep(0.5)

            def func3(num):
                for i in range(num):
                    print(gevent.getcurrent(), i)
                    time.sleep(0.5)

            def func4(num):
                for i in range(num):
                    print(gevent.getcurrent(), i)
                    time.sleep(0.5)

            def func5(num):
                for i in range(num):
                    print(gevent.getcurrent(), i)
                    time.sleep(0.5)
            def main():
                gevent.joinall([gevent.spawn(func1, 10),
                                gevent.spawn(func2, 10),
                                gevent.spawn(func3, 10),
                                gevent.spawn(func4, 10),
                                gevent.spawn(func5, 10)
                                ])
                                
            if __name__ == "__main__":
                main()
View Code

猜你喜欢

转载自www.cnblogs.com/wangxiongbing/p/10078869.html