python学习笔记——fork()建立多进程

1 进程概述

引自 Python 多进程 fork()详解html

1.1 进程

进程是程序的一次动态执行过程,它对应了从代码加载、执行到执行完毕的一个完整过程。python

进程是系统进行资源分配和调度的一个独立单位。进程是由代码(堆栈段)、数据(数据段)、内核状态和一组寄存器组成。 ubuntu

在多任务操做系统中,经过运行多个进程来并发地执行多个任务。因为每一个线程都是一个能独立执行自身指令的不一样控制流,所以一个包含多个线程的进程也可以实现进程内多任务的并发执行。 
进程是一个内核级的实体,进程结构的全部成分都在内核空间中,一个用户程序不能直接访问这些数据。 并发

进程的状态: 
建立、准备、运行、阻塞、结束。socket

1.2 进程间的通讯方式

1)文件  2)管道  3)socket  4)信号  5)信号量  6)共享内存函数

1.3 进程的建立函数

os.fork()ui

subprocessthis

processingspa

multiprocessing操作系统

 

2 建立进程

2.1 子进程的建立方式

Linux 和 Unix 操做系统提供了一个fork()函数建立新的进程,这也就意为这该函数仅适用于Linux和Unix平台。

fork()函数比较特殊,python的os.fork()是惟一调用一次返回两次的函数,因操做系统将当前的进程(父进程)复制了一份新的进程(子进程),而后分别在父进程和子进程内返回。

例如:采用父子进程拷贝文件,子进程的拷贝并非从开始就就行的(除非进行设置),混乱拷贝文件可能会出现结果异常而出现错误。

注意:有时在一个终端会混合出现打印结果。

fork() 函数原型

Help on built-in function fork in module posix: fork(...) fork() -> pid Fork a child process. Return 0 to child process and PID of child to parent process.

fork()从本质上属于内建函数,经过 os 模块导入

从函数原型上看,子进程永远返回0,而父进程则返回子进程的PID。这意味着每一个子进程的建立都会在父进程中留下标记PID(子进程身份信息),当子进程溯源其父进程时,经过getppid()就能够找到父进程的PID

 

fork()语法:

功能:为当前进程建立一个子进程

参数:无

返回值:0 和 子进程PID(在父进程中)

    < 0 子进程建立失败

    = 0 在子进程中的返回值

    > 0 在父进程中的返回值

特色:

(1)子进程会继承父进程几乎所有代码段(包括fork()前所定义的全部内容)

(2)子进程拥有本身独立的信息标识,如PID

(3)父、子进程独立存在,在各自存储空间上运行,互不影响

(4)建立父子进程执行不一样的内容是多任务中固定方法

关于父子进程详见对于多进程,子进程继承了父进程的内容fork以后子进程到底复制了父进程什么(这里面是C/C++内容,不过能够借鉴其思路)

 

2.2 建立简单的子进程:

import os pid = os.fork() if pid <0 : print("create process failed") elif pid == 0: print("this is child process") else : print("this is parent process") print("******the end*******")

运行:

this is parent process ******the end******* this is child process ******the end*******
#
this is parent process this is child process ******the end*******
******the end*******

运行的次数不一致时,会输出不一样结果

注:

(a)先后不一致的缘由,由于子进程和父进程独立运行,可是打印在同一个终端上,因此终端上父子进程同时打印出来。

(b)子进程运行时是从 pid = os.fork() 下面语句执行,实际上,该语句是两条语句, os.frok() 是建立子进程语句,而 pid =  是赋值语句,因此在建立完子进程后,下一句为运行赋值语句。

(c)该语句中,父进程先运行,运行中,子进程也运行,但此时并不表明父进程已经运行结束;因此出现终端语句混乱

(d)帮助理解父子进程空间

import os print('python课程') os.fork() print('Python多进程')

运行结果

python课程 Python多进程 Python多进程

 在该程序中,父进程建立一个子进程,父进程打印到终端“python多进程”,同时子进程也打印到终端“python多进程”,因此是两个“python多进程”。

(有资料显示父进程中建立了一个子进程,子进程运行打印了一个“python多进程”,回到父进程又打印了一个“python多进程”,因此结果是打印了2个“python多进程”。注:不知道两种描述那个符合程序运行过程,待考待查。)

2.3 添加时间调整执行顺序

import os from time import sleep pid = os.fork() if pid <0 : print("create process failed") elif pid == 0: sleep(3) print("this is child process") else : sleep(1) print("this is parent process") print("******the end*******")

运行结果:

this is parent process ******the end******* this is child process ******the end*******

注:

实际上其终端显示为

具体缘由我目前理解为父进程运行结束后,显示终端待输入命令,此时子进程没有运行,因此会显示上图情形;

当将父子进程sleep()时间变换一下,则为下面图结果

2.4 变量在父子进程中的关系

import os from time import sleep a = 10 #父子进程中含有相同的资源,包括fork()以前的语句 pid = os.fork() if pid < 0: print('create process failed') elif pid == 0: a = 1000 #子进程将a值修改成1000
    print("This is child process") else: sleep(2) print('a = ',a) print('The pid = ',pid) print("This is parent process") print('a = ',a) print("**********the end***********")

运行结果:

This is child process a =  1000
**********the end*********** a =  10 The pid =  5495 This is parent process a =  10
**********the end***********

注:

在父进程中变量的变量a=10,而在子进程中将其绑定为1000时,其在父进程中的绑定值并无变化。这主要是因父子进程中位于不一样的虚拟空间所致。

2.5 父子进程PID

os.getpid() 获取当前进程的PID号

os.getppid() 获取当前进程父进程的PID号

import os from time import sleep pid = os.fork() if pid < 0: print("create process failed") elif pid == 0: print("my PID is",os.getpid()) #子进程PID
    print("my parent process PID is",os.getppid()) #父进程PID
    print("this is child process") else: sleep(1) print("===========================") print("the PID is",pid) #父进程中fork()返回值 = 子进程PID
    print("the parent PID is",os.getpid()) #父进程PID
    print("this is parent process")

运行结果

my PID is 5815 my parent process PID is 5814 this is child process =========================== the PID is 5815 the parent PID is 5814 this is parent process

2.6 父子进程

import os from time import sleep pid = os.fork() if pid < 0: print("create process failed") elif pid == 0: print("my PID is",os.getpid()) #子进程PID
    print("my parent process-1 PID is",os.getppid()) #父进程PID
    sleep(5) print("my parent process-2 PID is",os.getppid()) #父进程PID
    print("this is child process") else: sleep(1) print("===========================") print("the PID is",pid) #父进程中fork()返回值 = 子进程PID
    print("the parent PID is",os.getpid()) #父进程PID
    print("this is parent process")

运行

my PID is 4338 my parent process-1 PID is 4337
=========================== the PID is 4338 the parent PID is 4337 this is parent process my parent process-2 PID is 2236 this is child process

注:在子进程中,sleep(5)先后的子进程对应的父进程是不同的(PID不一致),这是因为当父进程结束后,子进程就成了孤儿进程。

孤儿进程将被init进程(该进程号即为子进程新的父进程PID)所收养,并由init进程对它们完成状态收集工做。

在终端输入top可得到PID为2236对应信息

 COMMAND对应值为upstart;upstart即为ubuntux系统的一种init方式中的一种

附:目前Linux系统有三种init方式:第一种是最先的、也是广为流传的System V initialization; 第二种是最近几年提出的Upstart方式,基于事件机制,系统的全部服务和任务都是事件驱动的;最后一种是Systemd,发展最为迅速的,大有取代Upstart之势。本文主要是分析目前ubuntu(14.04)系统中所用的Upstart,....参看ubuntu的Upstart启动流程ubuntu upstart简单说明

改变程序,在父进程中增长死循环,不让父进程退出

import os from time import sleep pid = os.fork() if pid < 0: print("create process failed") elif pid == 0: print("my PID is",os.getpid()) #子进程PID
    print("my parent process-1 PID is",os.getppid()) #父进程PID
    sleep(5) print("my parent process-2 PID is",os.getppid()) #父进程PID
    print("this is child process") else: sleep(1) print("===========================") print("the PID is",pid) #父进程中fork()返回值 = 子进程PID
    print("the parent PID is",os.getpid()) #父进程PID
    print("this is parent process") while True: pass

此时就不会发生变化,由于父进程一直处于死循环未退出状态。

 

fork  侧重于父子进程都有任务,适合于少许的子进程建立

相关文章
相关标签/搜索