鱼C论坛

 找回密码
 立即注册
查看: 1744|回复: 1

[技术交流] 多任务篇章之(进程篇)

[复制链接]
发表于 2019-3-11 22:14:35 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 Stubborn 于 2019-3-11 23:58 编辑

多任务介绍(例如你需要运行多个软件,QQ,微信,浏览器,视频软件)
单核CPU的多任务实现:操作系统轮流让每个任务交替执行
多核CPU的多任务实现:真正的秉性执行多任务只能在多核CPU上实现,但由于任务数量远远多于CPU的核心数,所以操作系统也会自动把多个任务轮流调度到每个CPU核心上
并发:看上去一起执行,任务数多于CPU核心数
并行:真正一起执行,任务数小于等于CPU核心数
实现多任务的方式:
  • 多进程
  • 多线程
  • 多作程
  • 多进程+多线程

A进程:
对于系统而言,一个任务就是一个进程
进程是系统中程序执行和资源分配的基本单位。每个进程都有自己的数据段,代码段,和堆栈段。
A.1==>单任务
如下代码,只有一个主进程,执行到死循环,并不会反复执行run函数,
  1. from time import sleep

  2. def run():
  3.     while True:
  4.         print("sunck is a nice man")
  5.         sleep(1)
  6. if __name__ == '__main__':
  7.     while   True:  #任务1
  8.         print("sunck is a good man")
  9.         sleep(1)
  10.     #不会执行到run方法,只有上面的while循环结束,才可以执行
  11.     run()
复制代码


A.2==>启动多进程(同时执行任务与1任务2)
multiprocessing  库
跨平台的多进程模块,提供一个Process类来代表一个进程类对象
如代码块是上一个代码修改,加多一个子进程用来执行run函数,此时代码里面主进程在执行到死循环,子进程执行到run函数里面的死循环
  1. from multiprocessing import Process
  2. from time import sleep
  3. import os
  4. def run(str):
  5.     while True:
  6.         #os.getpid()获取当前进程ID号
  7.         #os.getppid()获取当前父进程的ID
  8.         print("sunck is a %s man---%s---%s"%(str,os.getpid(),os.getppid()))
  9.         sleep(1)

  10. if __name__ == '__main__':
  11.     print("主(父)进程启动----%s"%(os.getpid()))
  12.     #创建一个子进程
  13.     #target说明进程执行的任务(任务1run)
  14.     #args  需要传递的参数
  15.     p = Process(target=run,args=("nice",))
  16.     #启动进程
  17.     p.start()

  18.     while   True:  #任务2
  19.         print("sunck is a good man")
  20.         sleep(1)
复制代码


A.3==>父与子进程顺序
如果没有join(),那么主进程会直接结束掉,以为程序执行完毕。但是我们需要的是子进程为我们继续处理,或者运行。所以需要主进程等待子进程运行或者处理完毕之后在结束主进程
  1. from multiprocessing import Process
  2. from time import sleep
  3. import os

  4. def run(str):
  5.     print("启动子线程")
  6.     sleep(3)
  7.     print("结束子线程")

  8. if __name__ == '__main__':
  9.     print("主(父)进程启动----%s"%(os.getpid()))
  10.     p = Process(target=run,args=("nice",))
  11.     p.start()
  12.     #父进程的结束不能影响子进程
  13.     #让父进程等待子进程结束,再执行父进程
  14.     p.join()
  15.     print("父进程结束")
复制代码


A.4==>全局变量在多进程中,不会共享
  每个进程都有自己的数据段,代码段,和堆栈段。
  在子线程中对全局变量进行修改,对父进程中的全局变量没有影响
  在创建子进程时对全局变量做了一个备份,父与子进程中的num是2个完全不同的变量
  1. from multiprocessing import Process
  2. import os
  3. num = 100
  4. def run(str):
  5.     print("启动子线程")
  6.     global num
  7.     num += 1
  8.     print("结束子线程")

  9. if __name__ == '__main__':
  10.     print("主(父)进程启动----%s"%(os.getpid()))
  11.     p = Process(target=run,args=("nice",))
  12.     p.start()
  13.     #让父进程等待子进程结束,再执行父进程
  14.     p.join()
  15.     print("父进程结束---%d"%(num))
复制代码


A.5==>开辟大量子进程
  1. from multiprocessing import Pool
  2. import os,random,time
  3. def run(name):
  4.     print("启动%d子线程--%s"%(name,os.getpid()))
  5.     start = time.time()
  6.     time.sleep(random.choice([1,2,3]))
  7.     end = time.time()
  8.     print("结束%d子线程--%s--耗时%.2f"%(name,os.getpid(),end-start))

  9. if __name__ == '__main__':
  10.     print("主(父)进程启动----%s"%(os.getpid()))
  11.     #Pool:进程池 默认大小是CPU核心数
  12.     pp = Pool()
  13.     for i in range(17): #rang()大于CPU核心数,或者线程池数
  14.         #数量小于CPU核心,会同时启动,数量大于CPU核心,分批轮流启动
  15.         #子线程执行没有顺序
  16.         #创建进程,放入进程池统一管理
  17.         pp.apply_async(run,args=(i,))
  18.     #使用进程池,在调用join,必须先调用close,调用close不能添加新的进程
  19.     pp.close()
  20.     #进程池对象调用join,会等待经常池中所有的子进程结束在去执行父进程
  21.     pp.join()
  22.     print("父进程结束---"
复制代码


A.5.1==>开辟大量子进程,用于copy文件。函数与进程:
注:当文件比较小的时候,直接用函数copy比较快,因为开辟大量子进程比较消耗时间

  1. import os,time
  2. from multiprocessing import Pool
  3. # 循环函数实现
  4. # def copyFile(rpath,wpath):
  5. #     "copy文件"
  6. #     fr = open(rpath,"rb")
  7. #     fw = open(wpath,"wb")
  8. #     fw.write(fr.read())
  9. #     fr.close()
  10. #     fw.close()
  11. # rpath = r"C:\Users\Stubbron\Desktop\进程,线程\进程\file"
  12. # wpath = r"C:\Users\Stubbron\Desktop\进程,线程\进程\Tofile"
  13. # filelsit = os.listdir(rpath)
  14. # start = time.time()
  15. # for filename in filelsit:
  16. #     copyFile(os.path.join(rpath,filename),os.path.join(wpath,filename))
  17. # end = time.time()
  18. # print("耗时:%.2f"%(end-start))  #耗时:7.46  copy 1.54文件

  19. def copyFile(rpath,wpath):
  20.     "copy文件"
  21.     fr = open(rpath,"rb")
  22.     fw = open(wpath,"wb")
  23.     fw.write(fr.read())
  24.     fr.close()
  25.     fw.close()
  26. rpath = r"C:\Users\Stubbron\Desktop\进程,线程\进程\file"
  27. wpath = r"C:\Users\Stubbron\Desktop\进程,线程\进程\Tofile"

  28. if __name__ == '__main__':
  29.     filelsit = os.listdir(rpath)
  30.     start = time.time()
  31.     pp = Pool()
  32.     for filename in filelsit:
  33.         pp.apply_async(copyFile,args=(os.path.join(rpath,filename),os.path.join(wpath,filename)))
  34.     pp.close()
  35.     pp.join()
  36.     end = time.time()
  37.     print("耗时:%.2f" % (end - start))  #耗时:4.85   copy 1.54文件
复制代码



A.6==>封装进程对象
对封装进程对象的代码块可以单独写在一个模块,代码看起来比较整洁,也方便日后代码重构
  1. from multiprocessing import Process
  2. import os
  3. class StubbronProcess(Process):

  4.     def __init__(self,name):
  5.         Process.__init__(self)
  6.         self.name = name

  7.     def run(self):
  8.         print("子进程(%s--%s)启动"%(self.name,os.getpid()))
  9.         #子进程的功能
  10.         print("子线程要去干啥")
  11.         print("子进程(%s--%s)结束" % (self.name, os.getpid()))

  12. if __name__ == '__main__':
  13.     print("父进程启动")
  14.     #创建子进程
  15.     p = StubbronProcess("test")
  16.     #自动调用p进程对象的run方法
  17.     p.start()
  18.     p.join()
  19.     print("父进程结束")
复制代码


A.7==>进程间的“通讯”
利用到队列,数据原则是先进先出,后进后出。你用一个进程去产生某些数据,并存早列队里面,另外一个进程往这个列队取数据,实现进程之间的“通讯”
  1. from multiprocessing import Process,Queue
  2. import os,time
  3. def write(Q):
  4.     print("启动抓取子进程%s"%(os.getpid()))
  5.     for chr in ["A","B","C","D"]:
  6.         Q.put(chr)  #往队列传数据
  7.         time.sleep(1)
  8.     print("结束抓取子进程程%s" % (os.getpid()))

  9. def read(Q):
  10.     print("启动下载子进程%s"%(os.getpid()))
  11.     while True:
  12.         value = Q.get(True)  #没有数据,阻塞
  13.         print("value = ",value)
  14.     print("结束下载子进程%s" % (os.getpid()))

  15. if __name__ == '__main__':
  16.     #利用队列:由父进程创建队列,并传递给子进程,实现进程间的通讯
  17.     print("父进程启动")
  18.     q = Queue()
  19.     writ = Process(target=write,args=(q,))
  20.     rea = Process(target=read,args=(q,))
  21.     writ.start()
  22.     rea.start()
  23.     writ.join()
  24.     #rea进程里是个死循环,无法等待其结束 ,只能强行结束
  25.     rea.terminate()
  26.     print("父进程结束")
复制代码



本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-2-23 11:56:37 | 显示全部楼层
突然发现版主分享了很多看似高级但是非常基础内容,先看看哈,多谢分享,嘻嘻~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-5-14 18:55

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表