进程

概念:

进程:编写玩的程序没有运行称为程序,正在运行着称为进程

os.fork程序及说明

    import os

    # 注意,fork函数,只在Unix/Linux/Mac上运行,windows不可以
    pid = os.fork()

    if pid == 0:
        print('哈哈1')
    else:
        print('哈哈2')

说明:

  • 程序执行到os.fork()时,操作系统会创建一个新的进程(子进程),然后复制父进程的所有信息到子进程中
  • 然后父进程和子进程都会从fork()函数中得到一个返回值,在子进程中这个值一定是0,而父进程中是子进程的 id号
  • fork返回值   子进程中为0,父进程中为子进程的进程id码  返回值小于0时  创建进程失败
  • os.gepid当前进程,,,os.getppid。获取父进程的id

fork和process的区别:

  • 用fork产生的子进程,父进程结束之前是可以输入的,父进程结束,子进程成为孤儿进程,此时子进程当中的input输入会报错---原因是当成为孤儿进程时交给了后台进程处理,
  • process产生的子进程中遇到input输入直接就报错,关闭了input的操作

僵尸进程-孤儿进程

  • 僵尸进程:子进程先结束,父进程没有结束,并且父进程也没有回收子进程的资源,此时会产生僵尸进程
  • 孤儿进程:父进程结束,子进程没有结束,此时产生孤儿进程,此时的孤儿进程被特殊 进程收养
  • os.wait()会等待子进程结束并回收资源---不会产生僵尸进程
  • process.join()会等待子进程结束并回收资源---不会产生僵尸进程
  • process.start()会回收僵尸进程的资源
  • 主进程结束会将僵尸进程的资源回收

在Unix/Linux操作系统中,提供了一个fork()系统函数,它非常特殊。

普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程和子进程内返回。

子进程永远返回0,而父进程返回子进程的ID。

这样做的理由是,一个父进程可以fork出很多子进程,所以,父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程的ID。

代码:

import os

#
kpid = os.fork()

if kpid < 0:
    print('创建失败')
elif kpid == 0:
    print('我是子进程{},我的父进程为{}'.format(os.getpid(), os.getppid()))
else:
    print('我是父进程{},我的子进程为{}'.format(os.getpid(), kpid))

print('父子进程都能执行到')

 运行结果

我是父进程10213,我的子进程为10217
父子进程都能执行到
我是子进程10217,我的父进程为10213
父子进程都能执行到

多进程之间修改全局变量 

代码

import os

num = 1
kpid = os.fork()

if kpid < 0:
    print('创建失败')
elif kpid == 0:
    num += 1
    print(num)
    print('我是子进程{},我的父进程为{}'.format(os.getpid(), os.getppid()))
else:
    num += 1
    print(num)
    print('我是父进程{},我的子进程为{}'.format(os.getpid(), kpid))

print('父子进程都能执行到')

结果:

2
我是子进程10254,我的父进程为10253
父子进程都能执行到
2
我是父进程10253,我的子进程为10254
父子进程都能执行到
  • 多进程中,每个进程中所有数据(包括全局变量)都各有拥有一份,互不影响
  • 进程之间从逻辑上是隔离的不能通过全局变量传递数据,,全局变量也会被复制一份

两句fork的理解

父子进程的执行顺序

父进程、子进程执行顺序没有规律,完全取决于操作系统的调度算法

multiprocessing

此模块在windowns下也可以执行

Process的基本用法

import os
from multiprocessing import Process

def run_proc(name):
    print('子进程执行中{},pid={}'.format(name, os.getpid()))


if __name__ == '__main__':
    print('父进程开始执行{}'.format(os.getpid()))
    p = Process(target=run_proc, args=('test',))
    print('子进程开始执行')
    p.start()
    p.join()
    print('end')  

说明

  • 创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,用start()方法启动,这样创建进程比fork()还要简单。
  • join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步。

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值;

继承Process类

import os

from multiprocessing import Process

import time


class MyProcess(Process):
    def __init__(self, stop_time, name):
        Process.__init__(self)
        self.name = name
        self.stop_time = stop_time

    def run(self):
        print('{}子进程开始运行id为{}'.format(self.name,os.getpid()))
        print('正在运行中')
        time.sleep(self.stop_time)
        print('子进程执行结束')

if __name__ == '__main__':
    print('主进程开始执行{}'.format(os.getpid()))
    p = MyProcess(3, 'P1')
    # 对一个不包含target属性的Process类执行start()方法,就会运行这个类中的run()方法,所以这里会执行p1.run()
    p.start()
    p.join()
    print('主进程结束')
View Code

继承类Process 类之后,里面的run方法会在创建进程并启动会自动调用    如果手动在main方法里面调用那是父进程在执行  并没有让创建的进程执行

进程池

 

import os
import random
from multiprocessing import Pool
import time

print('主进程开始执行id为{}'.format(os.getpid()))

# 1.创建进程执行体
def run_func(name):
    print('{}开始执行进程号为{}'.format(os.getpid(), name))
    start_time = time.time()
    time.sleep(3)
    end_time = time.time()
    print('{}耗时{}'.format(name,end_time-start_time))
    print('{}结束执行进程号为{}'.format(os.getpid(), name))
    
# 2.创建进程池
my_pool = Pool(1)  # 注意定义进程池的位置,定义在任务执行体的后面

# 3.向进程池当中添加任务
for i in range(1,10):
    my_pool.apply_async(run_func, args=('Process-{}'.format(i),))
print('添加完成')

# 4.关闭进程池
my_pool.close()

# 5.阻塞进程池
my_pool.join()

print('主进程执行结束')

Poll返回的参数说明:

multiprocessing.Pool常用函数解析:

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

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

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

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

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

进程之间的队列

Queue的使用

可以使用multiprocessing模块的Queue实现多进程之间的数据传递,Queue本身是一个消息列队程序

消息队列的对象方法说明:

初始化Queue()对象时(例如:q=Queue()),若括号中没有指定最大可接收的消息数量,或数量为负值,那么就代表可接受的消息数量没有上限(直到内存的尽头);

  • Queue.qsize():返回当前队列包含的消息数量;

  • Queue.empty():如果队列为空,返回True,反之False ;

  • Queue.full():如果队列满了,返回True,反之False;

  • Queue.get([block[, timeout]]):获取队列中的一条消息,然后将其从列队中移除,block默认值为True;

1)如果block使用默认值,且没有设置timeout(单位秒),消息列队如果为空,此时程序将被阻塞(停在读取状态),直到从消息列队读到消息为止,如果设置了timeout,则会等待timeout秒,若还没读取到任何消息,则抛出"Queue.Empty"异常;

2)如果block值为False,消息列队如果为空,则会立刻抛出"Queue.Empty"异常;

  • Queue.get_nowait():相当Queue.get(False);

  • Queue.put(item,[block[, timeout]]):将item消息写入队列,block默认值为True;

1)如果block使用默认值,且没有设置timeout(单位秒),消息列队如果已经没有空间可写入,此时程序将被阻塞(停在写入状态),直到从消息列队腾出空间为止,如果设置了timeout,则会等待timeout秒,若还没空间,则抛出"Queue.Full"异常;

2)如果block值为False,消息列队如果没有空间可写入,则会立刻抛出"Queue.Full"异常;

  • Queue.put_nowait(item):相当Queue.put(item, False);

Queue实例

以Queue为例,在父进程中创建两个子进程,一个往Queue里写数据,一个从Queue里读数据:

 1 import os
 2 from multiprocessing import Queue,Process
 3 
 4 # 创建通信队列
 5 import time
 6 
 7 my_q = Queue(10)
 8 
 9 # 创建执行的函数
10 #
11 def write(q):
12     for i in ['wang', 'xiao', 'fei']:
13         q.put(i)
14         time.sleep(0.5)
15         print('{}进程成功写入{}'.format(os.getpid(),i))
16     print('写入结束')
17 #
18 def read(q):
19     while 1:
20         if not q.empty():
21             msg = q.get()
22             print('{}成功读取{}'.format(os.getpid(),msg))
23             time.sleep(0.5)
24         else:
25             print('{}进程执行结束'.format(os.getpid()))
26             break
27 
28 print("---start----")
29 # 创建两个进程 负责读取,与写入
30 p_w = Process(target=write, args=(my_q,))
31 p_r = Process(target=read, args=(my_q,))
32 p_w.start()
33 p_w.join()  # 等待全部写入后开始读取
34 p_r.start()
35 p_r.join()
36 print("---end----")
View Code

进程池中的Queue

 1 import os
 2 from multiprocessing import Pool, Manager
 3 
 4 import time
 5 
 6 
 7 def write_task(my_queue):
 8     for i in ("hello", "word", "prthon", "#end#"):
 9         my_queue.put(i)
10         print("%s进程已添加任务%s" % (os.getpid(), i))
11         time.sleep(1)
12 
13     print("%s进程已结束,,,," % os.getpid())
14 
15 
16 def read_task(my_queue):
17     while True:
18         msg = my_queue.get()
19 
20         if msg == "#end#":
21             print("%s进程读取结束......" % os.getpid())
22             break
23 
24         print("%s进程读取到的内容是%s" % (os.getpid(), msg))
25         time.sleep(1)
26 
27 
28 def main():
29     # 创建进程池
30     my_pool = Pool(2)
31 
32     # 创建队列
33     my_queue = Manager().Queue()  # 使用进程池创建的进程共享数据时必须使用该方法创建队列
34 
35     # 向进程池里面添加任务
36     my_pool.apply_async(write_task, args=(my_queue,))
37     my_pool.apply_async(read_task, args=(my_queue,))
38 
39     my_pool.close()
40     my_pool.join()  #
41     print("%s主进程任务结束" % os.getpid())
42 
43 
44 if __name__ == "__main__":
45     main()
View Code

 

posted @ 2017-09-01 19:39  凯哥吧  阅读(162)  评论(0)    收藏  举报