21.番外篇:Tornado的多进程管理分析---process.py代码解读
2016-05-29 14:32
441 查看
Tornado的多进程管理我们可以参看process.py这个文件。
在编写多进程的时候我们一般都用python自带的multiprocessing,使用方法和threading基本一致,只需要继承里面的Process类以后就可以编写多进程程序了,这次我们看看tornado是如何实现他的multiprocessing,可以说实现的功能不多,但是更加简单高效。
我们只看fork_process里面的代码:
这一段很简单,就是在没有传入进程数的时候使用默认的cpu个数作为将要生成的进程个数。
这是一个内函数,作用就是生成子进程。fork是个很有意思的方法,他会同时返回两种状态,为什么呢?其实fork相当于在原有的一条路(父进程)旁边又修了一条路(子进程)。如果这条路修成功了,那么在原有的路上(父进程)你就看到旁边来了另外一条路(子进程),所以也就是返回新生成的那条路的名字(子进程的pid),但是在另外一条路上(子进程),你看到的是自己本身修建成功了,也就返回自己的状态码(返回结果是0)。
所以if pid==0表示这时候cpu已经切换到子进程了,相当于我们在新生成的这条路上面做事(返回任务id);else表示又跑到原来的路上做事了,在这里我们记录下新生成的子进程,这时候children[pid]=i里面的pid就是新生成的子进程的pid,而 i就是刚才在子进程里面我们返回的任务id(其实就是用来代码子进程的id号)。
if id is not None表示如果我们在刚刚生成的那个子进程的上下文里面,那么就什么都不干,直接返回子进程的任务id就好了,啥都别想了,也别再折腾。如果还在父进程的上下文的话那么就继续生成子进程。
剩下的这段代码都是在父进程里面做的事情(因为之前在子进程的上下文的时候已经返回了,当然子进程并没有结束)。
pid,status = os.wait()的意思是等待任意子进程退出或者结束,这时候我们就把它从我们的children表里面去除掉,然后通过status判断子进程退出的原因。
如果子进程是因为接收到kill信号或者抛出exception了,那么我们就重新启动一个子进程,用的当然还是刚刚退出的那个子进程的任务号。如果子进程是自己把事情做完了才退出的,那么就算了,等待别的子进程退出吧。
我们看到在重新启动子进程的时候又使用了
主要就是退出子进程的空间,只在父进程上面做剩下的事情,不然刚才父进程的那些代码在子进程里面也会同样的运行,就会形成无限循环了,我没试过,不如你试试?
在编写多进程的时候我们一般都用python自带的multiprocessing,使用方法和threading基本一致,只需要继承里面的Process类以后就可以编写多进程程序了,这次我们看看tornado是如何实现他的multiprocessing,可以说实现的功能不多,但是更加简单高效。
我们只看fork_process里面的代码:
01 | global _task_id |
02 | assert _task_id is None |
03 | if num_processes is None or num_processes < = 0 : |
04 | num_processes = cpu_count() |
05 | if ioloop.IOLoop.initialized(): |
06 | raise RuntimeError( "Cannot run in multiple processes: IOLoop instance " |
07 | "has already been initialized. You cannot call " |
08 | "IOLoop.instance() before calling start_processes()" ) |
09 | logging.info( "Starting %d processes" , num_processes) |
10 | children = {} |
01 | def start_child(i): |
02 | pid = os.fork() |
03 | if pid = = 0 : |
04 | # child process |
05 | _reseed_random() |
06 | global _task_id |
07 | _task_id = i |
08 | return i |
09 | else : |
10 | children[pid] = i |
11 | return None |
所以if pid==0表示这时候cpu已经切换到子进程了,相当于我们在新生成的这条路上面做事(返回任务id);else表示又跑到原来的路上做事了,在这里我们记录下新生成的子进程,这时候children[pid]=i里面的pid就是新生成的子进程的pid,而 i就是刚才在子进程里面我们返回的任务id(其实就是用来代码子进程的id号)。
1 | for i in range (num_processes): |
2 | id = start_child(i) |
3 | if id is not None : |
4 | return id |
01 | num_restarts = 0 |
02 | while children: |
03 | try : |
04 | pid, status = os.wait() |
05 | except OSError, e: |
06 | if e.errno = = errno.EINTR: |
07 | continue |
08 | raise |
09 | if pid not in children: |
10 | continue |
11 | id = children.pop(pid) |
12 | if os.WIFSIGNALED(status): |
13 | logging.warning( "child , |
14 | id , pid,os.WTERMSIG(status)) |
15 | elif os.WEXITSTATUS(status) ! = 0 : |
16 | logging.warning( "child , |
17 | id , pid,os.WEXITSTATUS(status)) |
18 | else : |
19 | logging.info( "child , id , pid) |
20 | continue |
21 | num_restarts + = 1 |
22 | if num_restarts > max_restarts: |
23 | raise RuntimeError( "Too ) |
24 | new_id = start_child( id ) |
25 | if new_id is not None : |
26 | return new_id |
pid,status = os.wait()的意思是等待任意子进程退出或者结束,这时候我们就把它从我们的children表里面去除掉,然后通过status判断子进程退出的原因。
如果子进程是因为接收到kill信号或者抛出exception了,那么我们就重新启动一个子进程,用的当然还是刚刚退出的那个子进程的任务号。如果子进程是自己把事情做完了才退出的,那么就算了,等待别的子进程退出吧。
我们看到在重新启动子进程的时候又使用了
1 | if new_id is not None : |
2 | return new_id |
相关文章推荐
- Python动态类型的学习---引用的理解
- Python3写爬虫(四)多线程实现数据爬取
- 垃圾邮件过滤器 python简单实现
- 下载并遍历 names.txt 文件,输出长度最长的回文人名。
- install and upgrade scrapy
- Scrapy的架构介绍
- Centos6 编译安装Python
- 使用Python生成Excel格式的图片
- 让Python文件也可以当bat文件运行
- [Python]推算数独
- Python中zip()函数用法举例
- Python中map()函数浅析
- Python将excel导入到mysql中
- Python在CAM软件Genesis2000中的应用
- 使用Shiboken为C++和Qt库创建Python绑定
- FREEBASIC 编译可被python调用的dll函数示例
- Python 七步捉虫法