进程

一、解释什么是进程
  任务管理器:里面都是进程
  对于操作系统而言,一个任务就是一个进程

  进程是系统中程序执行和资源分配的基本单位,每个进程都有自己的数据段,代码段和堆栈段。
  数据段:存储数据
  代码段:存储代码
    堆:存储对象
    栈:存储普通变量
  两个特点:全局变量在多个进程之间不能共享
       多个进程在并行的时候,不会出现数据混乱
  进程的目的:实现多任务,提高我们的执行效率
  进程: 就是创建一个任务,让它去执行其他的功能
二、单任务现象
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 from time import sleep
 5 
 6 
 7 def run():
 8     while True:
 9         print("sunck is a nice man")
10         sleep(1.2)
11 
12 
13 if __name__ == '__main__':
14     while True:
15         print("sunck is a good man")
16         sleep(1)
17 
18 
19     # 不会执行 run 方法,只有上面的while循环结束才可以执行
20     # 要让这两个任务同时执行,就是多任务
21     run()
单任务现象

三、启动进程实现多任务

multiprocessing 库
multiple: adj.数量多的;多种多样的;
n.倍数;
processing: v.处理;加工;
n.过程;加工处理;处置;进行;
adj.经过特殊加工的;(用化学方法等)处理过的;

在linux下可以使用C语言的方法fork实现多进程,但是它不支持window,
但是这个三方库multiprocessing库是一个跨平台版本的多进程模块
提供了一个Process类来代表一个进程对象
所以我们要使用多进程就要引入multiprocessing库
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 import os
 5 from time import sleep
 6 
 7 from multiprocessing import Process
 8 
 9 
10 # 子进程需要执行的代码
11 def run(adj):
12     # os.getpid() 获取当前进程ID号
13     # os.getppid() 获取当前进程的父进程ID号
14     while True:
15         print("sunck is a %s man--%s--%s"%(adj, os.getpid(),os.getppid()))
16         sleep(1.2)
17 
18 
19 if __name__ == '__main__':
20     print("主(父)进程启动")
21     # os.getpid() 获取当前父进程ID号
22     print(os.getpid())
23 
24     # 创建一个子进程(在父进程下创建一个进程,故称为该进程的子进程)
25     p = Process(target=run, args=("nice",))
26     # target:说明 该子进程要执行的任务、代码、函数
27     # args:可以给target的函数传参数,是一个元组类型,单个参数要加逗号,
28 
29     # 启动进程
30     p.start()
31 
32     while True:
33         print("sunck is a good man")
34         sleep(1)
启动进程实现多任务

四、父子进程的先后顺序

  使用join(),让父进程等待子进程执行完毕,再执行。

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 from multiprocessing import Process
 5 from time import sleep
 6 
 7 def run(args):
 8     print("子进程启动")
 9     sleep(3)
10     print("子进程结束")
11 
12 if __name__ == '__main__':
13     print("主(父)进程启动")
14 
15     p = Process(target=run, args=("nice",))
16     p.start()
17 
18     # 父进程的结束不能影响子进程,让父进程等待子进程,再执行父进程
19     p.join()
20 
21     print("父进程结束")
父子进程的先后执行顺序

五、全局变量在多个子进程之间不能共享

  因为每个进程都会有自己独立的数据段,代码段,和堆栈段。

  每次创建新的进程的时候,该进程就会将全局变量做一个属于自己的备份。

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 from multiprocessing import Process
 5 from time import sleep
 6 
 7 NUM = 100
 8 
 9 
10 def run():
11     print("子进程开始")
12     global NUM
13     NUM += 1
14     print(NUM)
15     print("子进程结束")
16 
17 
18 if __name__ == '__main__':
19     print("父进程开始")
20     
21     p = Process(target=run)
22     p.start()
23     p.join()
24     
25     print(NUM)
26     # 在子进程中修改全局变量对父进程中的全局变量没有影响
27     # 为什么没影响呢?因为他在创建子进程时,对全局变量做了一个备份,父进程中的与子进程中的
28     # NUM是两个完全不同的变量
29     print("父进程结束--%d" % NUM)
全局变量在多个进程中不能共享

六、启动大量子进程(进程池)

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 import os
 5 import time
 6 import random
 7 
 8 # from multiprocessing import Process
 9 # 为了对多个进程好管理,使用进程池
10 from multiprocessing import Pool
11 
12 
13 def run(name):
14     print('子进程%s启动--%s' % (name, os.getpid()))
15     strat = time.time()
16     time.sleep(random.choice([1, 2, 3]))
17     end = time.time()
18     print('子进程%s结束--%s--耗时%.2f' % (name, os.getpid(), end-strat))
19 
20 
21 if __name__ == '__main__':
22     print('父进程启动')
23 
24     # 创建多个进程
25     # 进程池
26     # 4:表示可以同时执行的进程数量
27     # 参数可以写,也可以不写,不写pool默认大小是CPU核心数
28     pp = Pool(4)
29 
30     # 创建进程,创建的进程数要大于CPU核心数,这样才能体验到多进程的效果
31     # 这里因为进程都是干一样的活,所以使用for循环创建进程
32     # 子进程的执行顺序是没有顺序的。
33     for i in range(5):
34         # 创建进程,放进进程池,统一管理
35         pp.apply_async(run, args=(i,))
36 
37     '''
38     如果每个进程干的活不一样,那就单独创建每一个进程,不要写for循环。
39     例:
40     pp.apply_async(func1, agrs=())
41     pp.apply_async(func2, agrs=())
42     pp.apply_async(func3, agrs=())
43     pp.apply_async(func4, agrs=())
44     pp.apply_async(func5, agrs=())
45     '''
46 
47     # 在调用join之前,必须先调用close,并且在调用close之后,就不能再继续添加新的进程了
48     pp.close()
49     # 进程池对象调用的join,会等待进程池中的所有的子进程结束完毕,再去执行父进程。
50     pp.join()
51 
52     print("父进程结束")
53 
54 '''
55 运行结果:  这里进程看似0,1,2,3启动的,实际上,进程启动是没有顺序的。
56 父进程启动
57 子进程0启动--5251
58 子进程1启动--5252
59 子进程2启动--5253
60 子进程3启动--5254
61 子进程2结束--5253--耗时1.00
62 子进程0结束--5251--耗时1.00
63 子进程4启动--5253
64 子进程3结束--5254--耗时1.00
65 子进程1结束--5252--耗时2.00
66 子进程4结束--5253--耗时3.00
67 父进程结束
68 '''
启动大量子进程(进程池)

七、二次封装

  继承第三方的某各类,然后重写它的 init 方法,run 方法

 1 #二次封装的文件名,一般是:自己的名字+第三方库的名称
 2 
 3 import os
 4 import time
 5 from multiprocessing import Process
 6 
 7 
 8 class SunckProcess(Process):
 9     def __init__(self, name):
10         super().__init__()
11         self.name = name
12 
13     def run(self):
14         super().run()
15         print('子进程(%s-%s)启动' % (self.name, os.getpid()))
16         # 子进程的功能
17         time.sleep(3)
18         print('子进程(%s-%s)结束' % (self.name, os.getpid()))
sunckProcess
 1 from sunckProcess import SunckProcess
 2 
 3 
 4 if __name__ == '__main__':
 5     print('父进程启动')
 6 
 7     # 创建子进程
 8     p = SunckProcess('test')
 9     # 在这里不要调用进程里面的run方法,调用它的start就会自动调用进程对象的run方法
10     p.start()
11     p.join()
12 
13     print("父进程结束")
二次封装

八、进程间通信

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 import os
 5 import time
 6 from multiprocessing import Process
 7 from multiprocessing import Queue
 8 
 9 
10 def write(args):
11     print('启动写子进程%s' % (os.getpid()))
12     for letter in ['a', 'b', 'c', 'd']:
13         q.put(letter)
14         time.sleep(1)
15     print('结束写子进程%s' % (os.getpid()))
16 
17 
18 def read(args):
19     print('启动读子进程%s' % (os.getpid()))
20     while True:
21         value = q.get(True)
22         print('value = ' + value)
23     print('结束读子进程%s' % (os.getpid()))
24 
25 
26 if __name__ == '__main__':
27     # 父进程创建队列,并传递给子进程
28     q = Queue()
29     pw = Process(target=write, args=(q,))
30     pr = Process(target=read, args=(q,))
31 
32     pw.start()
33     pr.start()
34     #
35     pw.join()
36     # pr进程里面是个死循环,无法等待其结束,只能强行结束
37     pr.terminate()
38 
39     print('父进程结束')
进程间通信

 

 
posted @ 2018-12-02 21:55  狂奔蜗牛coding  阅读(206)  评论(0编辑  收藏  举报