• python中的多任务


    多任务

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

    线程

            特点
                查看正在运行的线程列表
                threading.enumerate()
                只要程序已启动,Python解释器就会自动创建一个主线程
                主线程等待其他线程结束后在结束
                线程target指向的函数执行完毕,线程就结束了
                子线程是调用start()之后开启的
                多个线程共享全局变量 
                
                    
            创建
                通过继承的方式创建线程
                    特点:写法复杂,使用简单,可以使用对象的特性(封装、继承、多态)业务逻辑比较复杂时使用
                方式一
                    import threading
                    p = threading.Thread(target=函数名,args=(1,))
              p.setDaemon(True) # 开启守护线程 p.start() p.join() 方式二
              # 线程类
    import threading class MyThread(threading.Thread): def run(): print('子线程要做的事') t = MyThread()
              t.setDaemon(True) 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.银行家算法

    队列

    from queue import Queue

    q
    = Queue(maxsize=100) item = {} q.put_nowait(item) #不等待直接放,队列满的时候会报错 q.put(item) #放入数据,队列满的时候回等待 q.get_nowait() #不等待直接取,队列空的时候会报错 q.get() #取出数据,队列为空的时候会等待 q.qsize() #获取队列中现存数据的个数 q.join() #队列中维持了一个计数,计数不为0时候让主线程阻塞等待,队列计数为0的时候才会继续往后执行 q.task_done() # put的时候计数+1,get不会-1,get需要和task_done 一起使用才会-1

    进程

         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.daemon = True # 开启守护进程 p.start() p.join() 方式二
    import multiprocessing class MyProcess(multiprocessing.Process): def run(): print("子进程要做的事情") p = MyProcess()
              p.daemon = True # 开启守护进程 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()

    协程

            什么是可迭代对象
                一个普通的对象实现了iter内置函数
            什么是迭代器
                一个普通的对象实现了iter和next内置函数
            迭代器的特点
                保存的是生成数据的方式,而不直接存储数据,好处:节省系统空间
            什么是生成器
                它是一个特殊的迭代器
            yield
                一个普通的函数里面写了yield的话,他就是一个生成器模板,执行函数遇到yield会阻塞,调用next()或者send()会解阻塞,end()可以用来传递参数
                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()    
  • 相关阅读:
    miaomiao
    你猜中了
    にあたり等
    厉害的走
    JavaWeb学习 第6章 Servlet和Cookie
    JavaWeb学习 第3章 servlet编程
    BinaryStar代码分析前言
    框架学习之Struts2 第九节 Struts2重要的标签解说
    框架学习之Struts2 第八节 OGNL表达式
    JavaWeb学习 第1章 Web开发工具配置和使用(下)Tomcat的配置
  • 原文地址:https://www.cnblogs.com/wangxiongbing/p/10078869.html
Copyright © 2020-2023  润新知