• Python档案袋( 进程与协程 )


    Python的进程和线程是使用的操作系统的原生线程和进程,其是去调用操作系统的相应接口实现

    进程:之间不可直接共享数据,是资源的集合,进程必须有一个线程

    线程:基于进程,之间可直接共享数据,可执行,只有所有的线程执行完毕程序才会退出

    守护线程:生命值依赖于创建它的主线程,主程序亡,不管守护进程执行到何步也必须立即亡

    多线程:不适用与CPU操作任务大的(如计算等),较适合于IO操作任务大的(如文件读写等)

    进程

    简单的进程

    Windows上启动进程必须加入【if __name__=="__main__":】,而在linux上则可随意,进程的使用基本与线程相同

    import multiprocessing
    import time
    
    def run11():
       print("-----  进程  ----")
    
    # win 进程启动,必须加入这句
    if __name__=="__main__":
        #启动进程
       t1=multiprocessing.Process(target=run11,args=())
       t1.start()

    进程间传递数据之进程队列:

     1 import multiprocessing
     2 
     3 def run11(qqlistx):
     4    print("****** 进入进程 ********")
     5    #设置进程数据
     6    qqlistx.put("11111122")
     7 
     8 # win 进程启动,必须加入这句
     9 if __name__=="__main__":
    10 
    11     #进程队列
    12     qqlistx = multiprocessing.Queue()
    13 
    14     #启动进程,必须传递进程队列
    15     t1=multiprocessing.Process(target=run11,args=(qqlistx,))
    16     t1.start()
    17 
    18     print("得到进程数据:", qqlistx.get())

    进程间传递数据之管道:

     1 import multiprocessing
     2 
     3 def run11(pp1):
     4    print("****** 进入进程 ********")
     5 
     6    #发送数据
     7    pp1.send("东小东")
     8    print("收到mian进程发来的数据:",pp1.recv())
     9 
    10 # win 进程启动,必须加入这句
    11 if __name__=="__main__":
    12 
    13     #得到管道
    14     # 得到两端,如同socket的服务器和客户端
    15     #任意一端都可以进行收发
    16     pp1,pp2 = multiprocessing.Pipe()
    17 
    18     #启动进程,传递任意一端
    19     t1=multiprocessing.Process(target=run11,args=(pp1,))
    20     t1.start()
    21 
    22     #另一端接收数据
    23     print("得到进程数据:", pp2.recv())
    24     pp2.send("收到数据了东小东")

    进程之数据共享:

    两个进程进行数据共享,列表或者字典数据共享

     1 import multiprocessing
     2 
     3 def run11(vv):
     4    print("****** 进入进程 ********")
     5 
     6    vv["dong"]="dongxiaodong"
     7    #vv.append("555") #列表
     8 
     9 # win 进程启动,必须加入这句
    10 if __name__=="__main__":
    11 
    12     #方法一  -------------:
    13     # with multiprocessing.Manager() as mssaagex:
    14     #       dictx=mssaagex.dict() #得到字典参数
    15     #       #listx=mssaagex.list() #得到列表参数
    16     #
    17     #       #启动进程,传递字典或者列表
    18     #       t1=multiprocessing.Process(target=run11,args=(dictx,))
    19     #       t1.start()
    20     #
    21     #       #等待进程接收
    22     #       t1.join()
    23     #
    24     #       #打印字典数据
    25     #       print("得到进程数据:", dictx)
    26 
    27      #方法二  -------------------:
    28      dictx=multiprocessing.Manager().dict() #得到字典参数
    29      #listx=multiprocessing.Manager().list() #得到列表参数
    30 
    31      #启动进程,传递字典或者列表
    32      t2=multiprocessing.Process(target=run11,args=(dictx,))
    33      t2.start()
    34 
    35      #等待进程接收
    36      t2.join()
    37 
    38      #打印字典数据
    39      print("得到进程数据:", dictx)

    进程锁:

    可以保护屏幕打印等,如多个进程同时向屏幕输出数据时,可以保证屏幕数据来自于一个进程,不会出现数据混乱问题

     1 import multiprocessing
     2 
     3 def run11(vv):
     4     vv.acquire() #上锁
     5     print("****** 进入进程 ********")
     6     vv.release()  #解锁
     7 
     8 
     9 # win 进程启动,必须加入这句
    10 if __name__=="__main__":
    11 
    12      lockx=multiprocessing.Lock() #得到进程锁
    13 
    14      t2=multiprocessing.Process(target=run11,args=(lockx,))
    15      t2.start()

    进程池:

    确定进程的同时运行个数,更好的进行进程管理

     1 import multiprocessing
     2 import time
     3 
     4 def run11(vv):
     5     time.sleep(1)
     6     print("****** 进入进程 ********",vv)
     7 
     8 #回调函数
     9 #在主进程中运行
    10 def Cal(arg):
    11     print("每个进程的回调函数",arg)
    12 
    13 # win 进程启动,必须加入这句
    14 if __name__=="__main__":
    15 
    16      poolx=multiprocessing.Pool(2) #得到进程池,最多同时执行2个进程
    17 
    18      #启动进程
    19      for i in range(10):
    20          #poolx.apply_async(func=run11,args=(i,)) #并行
    21          poolx.apply_async(func=run11,args=(i,),callback=Cal) #并行并加入执行完毕的回调函数
    22          #poolx.apply(func=run11,args=(i,)) #串行
    23 
    24      #等待并关闭进程
    25      poolx.close()
    26      poolx.join()
    27      print("-----  完毕  -----")

    协程:

    单线程实现高并发

    安装:pip3 install gevent

    手动切换:

    import greenlet
    
    def gfunx1():
        print("----gfunx1---")
        g2.switch() #手动切换到 gfunx2 中
    
    def gfunx2():
        print("---gfunx2----")
    
    #声明两个协程
    g1=greenlet.greenlet(gfunx1)
    g2=greenlet.greenlet(gfunx2)
    
    g1.switch() #手动切换到 gfunx1 中

    自动切换:

    默认是先运行完gfunx1然后再运行gfunx2,但当遇到IO操作则会自动跳转到另一个协程工作,以此实现在协程中遇到IO就互相切换执行的效果

     1 import gevent
     2 
     3 def gfunx1():
     4     print("---- gfunx1 ---")
     5     gevent.sleep(3) #模拟 IO 操作为 3 秒,但使用time.sleep(x)则会进行阻塞
     6     print("**** 三秒io操作结束 ******")
     7 
     8 def gfunx2():
     9     print("---- gfunx2 ----")
    10 
    11 
    12 #开启两个协程
    13 gevent.joinall([
    14     gevent.spawn(gfunx1),
    15     gevent.spawn(gfunx2),
    16 ])
    自动切换进阶:
    将一系列阻塞操作让协程识别为IO操作

     1 import gevent
     2 from gevent import monkey
     3 #将所有的阻塞操作(如:网络,延时,文件等)都视为gevent可捕获的IO阻塞操作
     4 #根据库作者提示:此句最好放在其它库import之前,否则会出现警告
     5 monkey.patch_all()
     6 
     7 import requests
     8 import time
     9 
    10 def gfunx1():
    11     print("---- gfunx1 ---")
    12     res=requests.get("https://img2018.cnblogs.com/blog/1485202/201811/1485202-20181116215233782-319594948.png")
    13     open("ww.jpg","wb").write(res.content) #以二进制写文件
    14     print("**** 网络操作结束 ******")
    15 
    16 def gfunx2():
    17     print("---- gfunx2 ----")
    18     time.sleep(3) #延时操作也已视为IO阻塞
    19     print("*** 延时操作结束 3s ***")
    20 
    21 def gfunx3(varx):
    22     print("---- gfunx3 ----",varx)
    23     time.sleep(1)
    24     print("*** 延时操作结束 1s ***")
    25 
    26 
    27  #开启三个协程
    28 gevent.joinall([
    29     gevent.spawn(gfunx1),
    30     gevent.spawn(gfunx2),
    31     gevent.spawn(gfunx3,"33333") #传递参数
    32  ])
  • 相关阅读:
    SystemTap----常用变量、宏、函数和技巧
    RPM制作
    percona-MYSQLGUI监控
    Rsyslog配置文件详解
    理解 Linux 网络栈(1):Linux 网络协议栈简单总结 图
    tcp-backlog配置
    Clumsy logo差网络环境模拟工具 Clumsy
    Android Studio 配置模拟器AVD存放路径(默认在c盘,解决c盘空间不够问题)
    Android Studio 导入的项目编码错误问题
    21分钟 MySQL 入门教程
  • 原文地址:https://www.cnblogs.com/dongxiaodong/p/10495501.html
Copyright © 2020-2023  润新知