1 进程概述

引自 Python 多进程 fork()详解

1.1 进程

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

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

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

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

1.2 进程间的通信方式

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

1.3 进程的创建函数

os.fork()

subprocess

processing

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  侧重于父子进程都有任务,适合于少量的子进程创建

python学习笔记——fork()创建多进程的更多相关文章

  1. python学习笔记(十三): 多线程多进程

    一.线程&进程 对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程, ...

  2. python学习笔记 | PyCharm创建文件时自动添加头文件

    File Settings Editor File and Code Templates Python Script 然后在右边的框中写入信息就可以啦: # -*- coding: utf-8 -*- ...

  3. Python学习笔记九

    Python学习笔记之九 为什么要有操作系统 管理硬件,提供接口. 管理调度进程,并且将多个进程对硬件的竞争变得有序. 操作系统发展史 第一代计算机:真空管和穿孔卡片 没有操作系统,所有的程序设计直接 ...

  4. python学习笔记--Django入门0 安装dangjo

    经过这几天的折腾,经历了Django的各种报错,翻译的内容虽然不错,但是与实际的版本有差别,会出现各种奇葩的错误.现在终于找到了解决方法:查看英文原版内容:http://djangobook.com/ ...

  5. OpenCV之Python学习笔记

    OpenCV之Python学习笔记 直都在用Python+OpenCV做一些算法的原型.本来想留下发布一些文章的,可是整理一下就有点无奈了,都是写零散不成系统的小片段.现在看 到一本国外的新书< ...

  6. python学习笔记(五岁以下儿童)深深浅浅的副本复印件,文件和文件夹

    python学习笔记(五岁以下儿童) 深拷贝-浅拷贝 浅拷贝就是对引用的拷贝(仅仅拷贝父对象) 深拷贝就是对对象的资源拷贝 普通的复制,仅仅是添加了一个指向同一个地址空间的"标签" ...

  7. Python学习笔记进阶篇——总览

    Python学习笔记——进阶篇[第八周]———进程.线程.协程篇(Socket编程进阶&多线程.多进程) Python学习笔记——进阶篇[第八周]———进程.线程.协程篇(异常处理) Pyth ...

  8. Python学习笔记(十一)

    Python学习笔记(十一): 生成器,迭代器回顾 模块 作业-计算器 1. 生成器,迭代器回顾 1. 列表生成式:[x for x in range(10)] 2. 生成器 (generator o ...

  9. Python学习笔记(八)

    Python学习笔记(八): 复习回顾 递归函数 内置函数 1. 复习回顾 1. 深浅拷贝 2. 集合 应用: 去重 关系操作:交集,并集,差集,对称差集 操作: 定义 s1 = set('alvin ...

随机推荐

  1. [21] Mesh法线的生成算法

    // 生成顶点法线 bool YfCalculateVertexNormal ( void* pNormalsBuffer, Yuint normalStriding, Yuint normalPos ...

  2. go语言基础之new函数

    1.new函数 表达式new(T)将创建一个T类型的匿名变量,所做的是为T类型的新值分配并清零一块内存空间,然后将这块内存空间的地址作为结果返回,而这个结果就是指向这个新的T类型值的指针值,返回的指针 ...

  3. 如何强制使用某一大小的包去ping某个IP地址?

    测试MTU的时候用得到的, 命令如下: ping -f -l 9000 10.110.68.40 ping命令的帮助输出如下: C:\Users\administrator>ping /? Us ...

  4. python 斐波拉契数列数列

    '''斐波拉契数列'''def Fibonacci(n): first, next = 0, 1 i = 0; while i < n: print next first, next = nex ...

  5. json字符串和dict互转

    json字符串和dict互转 import json str = '{"params":[{"id":222,"offset":0},{&q ...

  6. Java的泛型中,通配符可以设置上限和下限

    上限:<? extends T> ?是T和T的子类 下限:<? super T> ?是T和T的父类 怎么看待这个上限和下限呢 首先应该想 其实对于Java来说 <? ex ...

  7. Android实现Material Design风格的设置页面(滑动开关控件)

    前言 本文链接 http://blog.csdn.net/never_cxb/article/details/50763271 转载请注明出处 參考了这篇文章 Material Design 风格的设 ...

  8. 矩阵经典题目四:送给圣诞夜的礼品(使用m个置换实现对序列的转变)

    https://vijos.org/p/1049 给出一个序列,含n个数.然后是m个置换,求对初始序列依次进行k次置换,求最后的序列. 先看一个置换.把置换表示成矩阵的形式.然后将m个置换乘起来.那么 ...

  9. 记dynamic的一个小坑 -- RuntimeBinderException:“object”未包括“xxx”的定义

    创建一个控制台程序和一个类库, 在控制台创建一个匿名对象.然后再在类库中訪问它.代码例如以下: namespace ConsoleApplication1 { class Program { stat ...

  10. Android 之开发积累

    1.后台设置ImageView的src属性 有三种方式:img = (ImageView)this.findViewById(R.id.img_result_analyze); [1]setImage ...