添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

个人博客页面链接: http://www.shihao.online/ (django搭建的个人博客,还在完善中)

linux下使用fork()创建子进程

Linux 操作系统提供了一个 fork() 函数用来创建子进程,这个函数很特殊,调用一次,返回两次,因为操作系统是将当前的进程(父进程)复制了一份(子进程),然后分别在父进程和子进程内返回。子进程永远返回0,而父进程返回子进程的 PID(大于0)。我们可以通过判断返回值是不是 0 来判断当前是在父进程还是子进程中执行。

在 Python 中同样提供了 fork() 函数,此函数位于 os 模块下。

import os
import time
ret = os.fork()         #创建了一个子进程
if ret == 0:        #子进程
    while True:
        print("-------1--------")
        time.sleep(1)
else:               #父进程
    while True:
        print("-------2--------")
        time.sleep(1)

输出结果为:

-------2--------
-------1--------
-------1--------
-------2--------
-------1--------
-------2--------
-------1--------
-------2--------
-------1--------
-------2--------
-------1--------
-------2--------
-------1--------
-------2--------

无限循环。。。。。。(注:子进程和父进程的执行顺序不确定,即1和2输出顺序不一定,由操作系统的调度算法确定)

注意:如果父进程结束,子进程也跟着结束
如程序:

import os
import time
ret = os.fork()
if ret == 0:
    while True:
        print("---1-----")
        time.sleep(1)
else:
    print("---2-----")

输出结果为:

---2-----
---1-----

使用Process创建子进程

linux下可以使用fork创建子进程,但windows下不支持fork函数,但可以使用Process创建子进程

注意:与fork不同的是,主进程会等待Process子进程完成后结束。

Process语法结构如下:

Process([group [, target [, name [, args [, kwargs]]]]])

target:表示这个进程实例所调用对象;

args:表示调用对象的位置参数元组;

kwargs:表示调用对象的关键字参数字典;

name:为当前进程实例的别名;

group:大多数情况下用不到;

Process类常用方法:

is_alive():判断进程实例是否还在执行;

join([timeout]):是否等待进程实例执行结束,或等待多少秒;

start():启动进程实例(创建子进程);

run():如果没有给定target参数,对这个对象调用start()方法时,就将执行对象中的run()方法;

terminate():不管任务是否完成,立即终止;

Process类常用属性:

name:当前进程实例别名,默认为Process-N,N为从1开始递增的整数;

pid:当前进程实例的PID值;

from multiprocessing import Process
import time
import random
def test():
    for i in range(1,5):
        print("---%d---"%i)
        time.sleep(1)
p = Process(target=test)
p.start()   #让这个进程开始执行test函数里面的代码
p.join()     #等进程p结束之后,才会继续向下走
print("---main----")

输出结果为:

---1---
---2---
---3---
---4---
---main----

进程池创建子进程

当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态成生多个进程,但如果是上百甚至上千个目标,手动的去创建进程的工作量巨大,此时就可以用到multiprocessing模块提供的Pool方法。

初始化Pool时,可以指定一个最大进程数,当有新的请求提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来执行.

multiprocessing.Pool常用函数解析:

apply_async(func[, args[, kwds]]) :使用非阻塞方式调用func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func的参数列表,kwds为传递给func的关键字参数列表;

apply(func[, args[, kwds]]):使用阻塞方式调用func

close():关闭Pool,使其不再接受新的任务;

terminate():不管任务是否完成,立即终止;

join():主进程阻塞,等待子进程的退出, 必须在close或terminate之后使用;

程序(非阻塞方式):

from multiprocessing import Pool
import os
import time
def worker(num):
    for i in range(2):
        print("===pid=%d===num=%d"%(os.getpid(), num))
        time.sleep(1)
pool = Pool(3)  #定义一个进程池,最大进程数3
for i in range(5):
    print("---%d---"%i)
    pool.apply_async(worker, [i,])    #使用非阻塞方式调用func(并行执行,堵塞方式必须
                                      #等待上一个进程退出才能执行下一个进程)
print("---start----")
pool.close()    #关闭进程池,关闭后pool不能再添加新的请求
pool.join()     #等待pool中所有子进程执行完成,必须放在close语句之后
print("---end----")
---0---
---1---
---2---
---3---
---4---
---start----
===pid=24958===num=0
===pid=24959===num=1
===pid=24960===num=2
===pid=24958===num=0
===pid=24960===num=2
===pid=24959===num=1
===pid=24960===num=3
===pid=24958===num=4
===pid=24960===num=3
===pid=24958===num=4
---end----

程序(阻塞方式):

from multiprocessing import Pool
import os
import time
def worker(num):
    for i in range(2):
        print("===pid=%d===num=%d"%(os.getpid(), num))
        time.sleep(1)
pool = Pool(3)  #定义一个进程池,最大进程数3
for i in range(5):
    print("---%d---"%i)
    pool.apply(worker, [i,])    #使用非阻塞方式调用func(并行执行,堵塞方式必须
                                      #等待上一个进程退出才能执行下一个进程)
print("---start----")
pool.close()    #关闭进程池,关闭后pool不能再添加新的请求
pool.join()     #等待pool中所有子进程执行完成,必须放在close语句之后
print("---end----")
---0---
===pid=24999===num=0
===pid=24999===num=0
---1---
===pid=25000===num=1
===pid=25000===num=1
---2---
===pid=25001===num=2
===pid=25001===num=2
---3---
===pid=24999===num=3
===pid=24999===num=3
---4---
===pid=25000===num=4
===pid=25000===num=4
---start----
---end----

注意:进程池和fork()一样,不会等待子程序结束

from multiprocessing import Pool
import os
import time
def worker():
    for i in range(2):
        print("===pid=%d==="%os.getpid())
        time.sleep(1)
pool = Pool(3)  #定义一个进程池,最大进程数3
for i in range(5):
    print("---%d---"%i)
    pool.apply_async(worker)    #使用非阻塞方式调用func(并行执行,堵塞方式必须
                                #等待上一个进程退出才能执行下一个进程)
---0---
---1---
---2---
---3---
---4---
                                    fork()函数用于从已存在的进程创建一个新进程。新进程称为子进程,而园进程称为父进程。使用fork()函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空间,包括进程的上下文、代码段、进程堆栈、内存信息、打开的文件描述符、符号控制设定、进程优先级、进程组号、当前工作目录、根目录、资源限制和控制终端等,而子进程所独有的只有它的进程号、资源使用和计时器等。
因为子进程几乎是父进程的完全复制,所以父子两进程会运行同一个程序。这就需要用一种方式来区分它们,并使它们照此运行,否则,这两个进程不可能做不同的事。实际上是在父进程中执行fork()函数时,父进程会复制一个子进程,而且父
                                    要让Python程序实现多进程(multiprocessing),我们先了解操作系统的相关知识。
Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊。普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程子进程内返回。
子进程永远返回0,而父进程返回子进程的ID。这样做的...
                                    开启多进程几种方法
1. 使用多个进程启动多个Tornado实例
2. 使用tornado.process.fork_processes()方法启动多个进程
3.使用标准库中的multiprocessing
4.使用第三方模块gevent
5.使用官方提供方式
6.使用supervisor
以下各种方式仅供参考,本人亲测只有官方提供的方式比较靠谱。
1. 使用多个进程启动多个Tornado实例
fork()系统调用是Unix下以自身进程创建子进程的系统调用,
一次调用,两次返回,如果返回是0,
则是子进程,如果返回值>0,则是父进程(返回值是子进程的pid)
source = 10
i = 0
  print '***********************'
  pid = os.fork()
  #这里会返回两次,所以下面的省略号会输出2次
  print '......'
pid=os.fork()
  1.只用在Unix系统中有效,Windows系统中无效
  2.fork函数调用一次,返回两次:在父进程中返回值为子进程id,在子进程中返回值为0
import os
pid=os.fork()
if pid==0:
  print(执行子进程子进程pid={pid},父进程ppid={ppid}.format(pid=os.getpid(),ppid=os.getppid()))
else:
  print(执行父进程子进程pid={pid},父进程ppid
该函数创建子进程具体fork的过程:
(1)调用该函数即创建一个子进程创建成功父进程返回子进程的pid,子进程返回0;
(2)创建子进程实际上对父进程的一个拷贝,共享代码空间,拷贝父进程的数据,也就是说父进程改变父进程的数据,子进程改变子进程的数据变量等;
二、示例代码分析
代码示例:
  $curr_pid = posix_getpid();//获取当前的进程id
  //将当前进程的id写入文件中
  echo '当前进程:'.$cu
                                    celery在容器运行,总是突然暴毙,查看日志发现如下错误:
Process 'ForkPoolWorker-170' pid:181 exited with 'signal 9 (SIGKILL)
解决办法:
由于celery在容器里面运行, 只分配了了一核, 导致的错误, 将配置升高核数, 问题解决
                                    问题描述celery的worker端报错:-------------- worker2@zheng-VirtualBox v4.2.0 (windowlicker)---- **** ----- --- * ***  * -- Linux-4.15.0-20-generic-x86_64-with-Ubuntu-18.04-bionic 2018-07-02 10:13:33-- * - ****...
                                    1.os.fork():主进程执行完退出,不会等待子进程子进程不会随着主进程结束,继续运行。
2.Process():主进程会等待子进程结束后,在结束整个程序。
3.Pool():主进程不会等待子进程,主进程结束后,整个程序都结束。可创建多个进程。
例:fork
import os,time
num = 0
pid = os.fork()
if pid == 0:
    time.sl
                                    1  进程的基本概念
什么是进程进程就是一个程序在一个数据集上的一次动态执行过程。进程一般由程序、数据集、进程控制块三部分组成。我们编写的程序用来描述进程要完成哪些功能以及如何完成;数据集则是程序在执行过程中所需要使用的资源;进程控制块用来记录进程的外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感知进程存在的唯一标志。
进程的过程: 创建, 就绪, 运行 ,阻塞, ...
                                    flask + celery
此报错是因为celery任务超过了 hard_time_limit 时间被celery主进程kill掉了,  应该还能找到此报错: MainProcess Hard time limit (300s) exceeded for (此处设置的hard_time_limit为300s)
把soft_time_limit设置少于hard_time_limit, 并进行异常捕获处理即可
查到公司原代码hard_time_limit为300s  soft_time
windows上不支持,mac,linux,unix上可以
import os  
pid = os.fork()  # 操作系统自动把父进程的信息资源复制给了子进程,在两个进程中分别返回,父进程返回子进程的ID
if pid < 0:
    print('fork失败')
elif pid == 0:  # 子进程的pid为 0
    print('我是子进程',os.getpid(),'我的父进程',os.getppid())  # os.getpid()获取当前进
                                    fork()
python中的os模块封装了常见的系统调用,其中fork可以轻松的创建子进程
注意:fork只能在unix,linux,mac上运行,windows不能运行
import os 
ret = os.fork()   #创建子进程,函数返回一个值,子进程中这个值一定为0,父进程得到的是子进程的pid号
if ret == 0:
    while True:
        prin...
                                    文章目录1.模块1.2.Process类1.3参数:1.4属性介绍1.5绑定方法2.开启子进程的两种方式2.1方式12.2方式23.进程数据隔离4.方法及属性4.1 .join()方法4.2 进程状态4.3进程名称与PID4.4守护进程5.进程同步与互斥锁5.1 抢票模拟6.队列6.1队列方法6.2生产消费模型7.信号量8.Event时间
Python中的多线程无法利用多核优势,可以通过去他的模块去实现(不常用)。
Python中大部分情况下需要使用多进程,内置multiprocessing模块,