并发编程之多进程

一 多进程

我们今天主要讲了进程的创建:

进程的创建分为四种:其中在进程中开启子进程是我们讲的重点。

   1. 系统初始化(查看进程linux中用ps命令,windows中用任务管理器,前台进程负责与用户交互,后台运行的进程与用户无关,
运行在后台并且只在需要时才唤醒的进程,称为守护进程,如电子邮件、web页面、新闻、打印)   
2. 一个进程在运行过程中开启了子进程(如nginx开启多进程,os.fork,subprocess.Popen等)   3. 用户的交互式请求,而创建一个新进程(如用户双击暴风影音)   4. 一个批处理作业的初始化(只在大型机的批处理系统中应用)

  无论哪一种,新进程的创建都是由一个已经存在的进程执行了一个用于创建进程的系统调用而创建的:

  1. 在UNIX中该系统调用是:fork,fork会创建一个与父进程一模一样的副本,二者有相同的存储映像、同样的环境字符串和同样的打开文件(在shell解释器进程中,执行一个命令就会创建一个子进程)

  2. 在windows中该系统调用是:CreateProcess,CreateProcess既处理进程的创建,也负责把正确的程序装入新进程。

二  进程开启的两种方式:

开启子进程方式一:
from multiprocessing import Process
import time
def run(name):
    time.sleep(2)
    print('%s is running'%name)
if __name__ == '__main__':
    t=Process(target=run,args=('feng',))
    t=Process(target=func,kwargs={'name':'feng'})#args与kwargs是一样的只是形式不同而已。
    t.start()###### 向操作系统发送请求,操作系统会申请内存空间,然后把父进程的数据拷贝给子进程,位子进程的数据初始化。
    print('zhu'.center(50,'*'))          
运行结果为:

***********************zhu************************
feng is running

整个程序的运行其实就是,先定义一个函数run,然后运行主程序,在运行主程序的的过程创建一个子进程,子进程具体是由操作系统来创建的。而创建一个子程序所需要的时间远大于运行一行代码,所以首先打印出***********************zhu************************,然后子进程开始运行,输出feng is running

方式二:
from multiprocessing import Process
import  time
class MyProcess(Process):
    def __init__(self,name):
        super().__init__()
        self.name=name
    def run(self):
        time.sleep(2)
        print('%s is running'%self.name)
if __name__ == '__main__':
t=MyProcess('feng')
t.start()
print('zhu'.center(50,'='))
运行结果为:

=======================zhu========================
feng is running

整个程序的运行,先定义一个类。

下面我们子进程与父进程的关系:

    1 在内存中进程之间是互相隔离的:

from multiprocessing import Process
import time
x=1000
def run(name):
    global x
    x=0
    time.sleep(2)
    print('%s is running'%name,x)
if __name__ == '__main__':
    t=Process(target=run,args=('feng',))
    t.start()#在这里子进程启动,其实就是调用父进程中的run,执行,
    time.sleep(5)
    print(x)
运行结果:

feng is running 0
1000

x=1000,是定义阶段就确定的,所以主进程的x不会随着在子进程中的改变而改变,而如果我们在子进程中打印x,那么就是改变后的值。

通过这个过程我们可以看出,子进程与父进程的内存空间是独立的。也就是说,子进程的改变不会影响父进程。父进程不会执行run内的代码。

     2  join用法:就是让父进程等子进程运行结束再运行。

我们讲的jion的用法:
from multiprocessing import Process
import time
x=1000
def task():
    time.sleep(3)
    global  x
    x=0
    print('儿子结束了',x)

if __name__ == '__main__':
    print(x)
    p=Process(target=task,)
    p.start()
    p.join()    ##让父亲在原地等。等到子进程运行结束后父进程才会继续运行。
    print(x)
# 运行结果为:
'''
1000
儿子结束了 0
1000'''

  3  子进程实现并发:

# from multiprocessing import Process
# import time
#
# def task(n):
#     print('%s is running'%n)
# if __name__ == '__main__':
#     for i in range(1,4):
#         p=Process(target=task,args=(i,))
#         p.start()
#
#     print('主'.center(20,'='))
# # 输出结果为:
# '''
# =========主==========
# 3 is running
# 1 is running
# 2 is running'''#为什么输出结果为无序的呢:那是因为start只是向操作系统发出请求,创建子进程,那么创建完子进程嗯么运行
#这完全是由操作系统控制的了。

   4 join与并发:

方式一:比较low的方式
from
multiprocessing import Process import time def task(n): print('%s is running'%n) time.sleep(3) if __name__ == '__main__': p1=Process(target=task,args=(1,)) p2 = Process(target=task, args=(2,)) p3 = Process(target=task, args=(3,)) p1.start() p2.start() p3.start() p1.join() p2.join() p3.join() print('') # 运行结果为: ''' 2 is running 1 is running 3 is running
方式二:使用循环:
from multiprocessing import Process
import time
def task(n):
    print('%s is running'%n)
    time.sleep(3)

if __name__ == '__main__':
#     start_time=time.time()
# p_list=[]
# for i in range(1,4):
# p=Process(target=task,args=(i,))
# p_list.append(p)
# p.start()
# for p in p_list:
# p.join()
# print('主',time.time()-start_time)
运行结果:
# '''
# 2 is running
# 1 is running
# 3 is running
# 主 2.1594531536102295
# '''

   5 查看进程id也就是pid

# from multiprocessing import Process
# import time,random
# import os
#
# def task():
#     time.sleep(2)
#     print('me:%s,father:%s'%(os.getpid(),os.getppid()))
# if __name__ == '__main__':
#     p2=Process(target=task,)
#     p2.start()
#     # p2.join()
#
#     print(p2.name,p2.pid)
#     print('主',os.getppid())
print('主',os.getpid())#这个输出的结果是跟子进程的father是一样的。
print('主',os.getppid())#而这个输出的结果为pycha的pid。

# # 运行结果为: # ''' # Process-1 8200 # 主 3428 # me:8200,father:4940'''

僵尸进程:子进程死了,父进程还在(父进程大量造子进程,导致大量pid被占用),僵尸进程是有害的。

孤儿进程:父进程先结束,子进程由init来管理子进程,孤儿进程是无害的。

猜你喜欢

转载自www.cnblogs.com/zhangsanfeng/p/8931226.html