Python进程-实现

fork介绍

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

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

Python的os模块封装了常见的系统调用

import os

if __name__ == '__main__':

    print('进程 (%s) start...' % os.getpid())
    pid = os.fork()
    # time.sleep(10)
    if pid == 0:  # 子进程fork()返回0
        print("子进程{},父进程{}".format(os.getpid(), os.getppid()))
    else:  # 父进程fork返回子进程的id
        print("父进程{},子进程{}".format(os.getpid(), pid))

--》》结果
进程 (3130) start...
父进程3130,子进程3131
子进程3131,父进程3130

 

multiprocessing模块介绍

python中的多线程无法利用CPU资源,在python中大部分计算密集型任务使用多进程。如果想要充分地使用多核CPU的资源(os.cpu_count()查看)

python中提供了非常好的多进程包multiprocessing。

multiprocessing模块用来开启子进程,并在子进程中执行功能(函数),该模块与多线程模块threading的编程接口类似。

multiprocessing的功能众多:支持子进程、通信和共享数据、执行不同形式的同步,提供了Process、Queue、Pipe、Lock等组件。

 计算密集型任务:如金融分析,科学计算

注意

记住,进程的执行是有操作系统调度的,python执行进程(start)只是向操作系统发信号,告诉操作系统,我要开辟一个进程,由操作系统调度执行。

同理,python终止进程(terminate)只是向操作系统发信号,告诉操作系统,我要终止一个进程,而不会马上终止,由操作系统调度终止进程。

Process类的介绍

1.创建进程的类

 

Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,表示一个子进程中的任务(尚未启动)

强调:
1. 需要使用关键字的方式来指定参数
2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号

2.参数介绍

group参数未使用,值始终为None

target表示调用对象,即子进程要执行的任务

args表示调用对象的位置参数元组,args=(1,2,'al',)

kwargs表示调用对象的字典,kwargs={'name':'al','age':18}

name为子进程的名称

3.方法介绍

p.start():启动进程,并调用该子进程中的p.run() 
p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法  

p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。
如果p还保存了一个锁那么也将不会被释放,进而导致死锁
p.is_alive():如果p仍然运行,返回True

p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,
需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程

4.属性介绍

p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置

p.name:进程的名称

p.pid:进程的pid

p.exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可)

p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,
这类连接只有在具有相同的身份验证键时才能成功(了解即可)

Process类的使用

 

注意:在windows中Process()必须放到# if __name__ == '__main__':下

开一个进程和主进程是并发的关系,我start一下就是先告诉操作系统我要开一个进程
,然而它不会等待,他会去执行下面的代码,完了他把进程开始后,就开始执行了

 

# window创造进程相当于导入,会无线递归创建
# Linux 是把父进程拷贝到子进程
import multiprocessing
import time
import threading

print('main process start1')
def func():
    print('subprocess start',time.asctime(time.localtime(time.time())))
    time.sleep(3)
    print('subprocess end',time.asctime(time.localtime(time.time())))

print('main process start2')
p = multiprocessing.Process(target=func, name='1号')
p.start()
print('main process end', time.asctime(time.localtime(time.time())),multiprocessing.current_process())
if __name__ == '__main__':
    pass
    # 默认所有进程结束后,程序才结束

"""
linux 
main process start1
main process start2
main process end Fri Mar 23 00:20:29 2018 <_MainProcess(MainProcess, started)>
subprocess start Fri Mar 23 00:20:29 2018
subprocess end Fri Mar 23 00:20:32 2018

"""

"""
windows
Make sure that the main module can be safely 
imported by a new Python interpreter without causing unintended 
side effects (such a starting a new process)."

main process start1 
main process start2
main process end Fri Mar 23 00:23:50 2018 <_MainProcess(MainProcess, started)>
main process start1 #相当于导入一次该程序,在main函数之前调用进程,会造成无限循环输出导致报错
subprocess start Fri Mar 23 00:23:50 2018
subprocess end Fri Mar 23 00:23:53 2018

"""

 strat():方法的功能

  1.开启进程
  2.执行功能

开启进程方法一

import time
import multiprocessing
# import threading

def func():
    i = 0
    for _ in range(10000000):
        i += 1
    return  True

def main():
    start = time.time()
    p = multiprocessing.Process(target=func)  # 创建一个子进程
    p1 = multiprocessing.Process(target=func)
    p.start()
    p1.start()
    # p = threading.Thread(target=func)
    # p.start()
    func()
    end = time.time()
    print(end - start)

if __name__ == '__main__':
    main()

开启进程方法二

from multiprocessing import Process
import time
import random
import os
class pro(Process):
    def __init__(self,name):
        super().__init__() # 必须继承父类的一些属性
        self.name = name
    def run(self):  # 必须得实现一个run方法
        print('%s is work,父进程%s,当前进程%s'%(self.name,os.getppid(),os.getpid()))
        time.sleep(1)
        print('%s is work end'%self.name)
if __name__ =='__main__':
    p1 = pro('al')
    p2 = pro('b1')
    p3 = pro('c1')
    p1.start()
    p2.start()
    p3.start()
    print('主进程',os.getpid())

-》》输出
主进程 9116
b1 is work,父进程9116,当前进程4316
al is work,父进程9116,当前进程6664
c1 is work,父进程9116,当前进程10132
b1 is work end
al is work end
c1 is work end

使用daemon

  1. 守护进程会在主进程代码执行结束后就终止
from multiprocessing import Process
import time
import random
import os
class My_Process(Process):
    def __init__(self,name):
        super().__init__() # 必须继承父类的一些属性
        self.name = name

    def run(self):  # 必须得实现一个run方法
        time.sleep(5)
        print('%s is work end'%self.name)

if __name__ =='__main__':
    start_time = time.time()
    print("process start")
    for i in range(5):
        t = My_Process('Process%s' % i)
        # t.daemon = True
        t.start()
    time.sleep(3)
    print("process end")
    print(time.time() - start_time)

"""
 t.daemon = False
process start
process end  #主进程运行完毕后,程序等待子进程运行完成后结束
0.020070791244506836
Process0 is work end
Process2 is work end
Process3 is work end
Process4 is work end
Process1 is work end

Process finished with exit code 0
"""


"""
 t.daemon = True
process start
process end   #主进程运行完毕后,守护进程结束
3.014104127883911

Process finished with exit code 0
"""

2. 守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes are not allowed to have children

from multiprocessing import Process
import time
import random

def task(name):
    print('%s is start' %name)
    time.sleep(random.randrange(1,3))
    print('%s is end' %name)
    p = Process(target=time.sleep, args=(3,)) #在守护进程里面开子进程报错
    p.start()


if __name__ == '__main__':
    p=Process(target=task,args=('egon',))
    p.daemon=True #一定要在p.start()前设置,设置p为守护进程,禁止p创建子进程,并且父进程代码执行结束,p即终止运行

    p.start()
    p.join()
    print('主') #只要终端打印出这一行内容,那么守护进程p也就跟着结束掉了
-----------

egon is start
egon is end
Process Process-1:
Traceback (most recent call last):
  File "C:\Program Files\Python36\lib\multiprocessing\process.py", line 249, in _bootstrap
    self.run()
  File "C:\Program Files\Python36\lib\multiprocessing\process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "C:\Users\jingjing\PycharmProjects\py3Project\路飞\第四模块课件\01网络编程进阶\01 多进程\05 守护进程.py", line 55, in task
    p.start()
  File "C:\Program Files\Python36\lib\multiprocessing\process.py", line 103, in start
    'daemonic processes are not allowed to have children'
AssertionError: daemonic processes are not allowed to have children
主

思考下列代码的执行结果有可能有哪些情况?为什么?

from multiprocessing import Process

import time
def foo():
    print(123)
    time.sleep(1)
    print("end123")

def bar():
    print(456)
    time.sleep(3)
    print("end456")

if __name__ == '__main__':
    p1=Process(target=foo)
    p2=Process(target=bar)

    p1.daemon=True
    p1.start()
    p2.start()
    print("main-------")


-----输出
main-------
456
end456
当输出main之后,守护进程就结束了

  

使用terminate

import multiprocessing
import time
import threading


def func():
    print('subprocess start',time.asctime(time.localtime(time.time())))
    time.sleep(3)
    print('subprocess end',time.asctime(time.localtime(time.time())))

if __name__ == '__main__':
    p = multiprocessing.Process(target=func, name='1号')
    p.start()
    p.terminate() # 终止进程
    time.sleep(5)
    print(p.is_alive()) # 判断这个进程是否存在
    # 默认所有进程结束后,程序才结束
    print('main process end', time.asctime(time.localtime(time.time())), multiprocessing.current_process())

-》》》输出
""" False 终止进程后is_alive()返回False,没有执行print('subprocess s…… main process end Fri Mar 23 17:22:57 2018 <_MainProcess(MainProcess, started)> """

使用join

import multiprocessing
import time
import threading


def func():
    print('subprocess start',time.asctime(time.localtime(time.time())))
    time.sleep(3)
    print('subprocess end',time.asctime(time.localtime(time.time())))

if __name__ == '__main__':
    p = multiprocessing.Process(target=func, name='1号')
    p.start()
    p.join() # 等待子进程完成后,结束主线程
    # 默认所有进程结束后,程序才结束
    print('main process end', time.asctime(time.localtime(time.time())), multiprocessing.current_process())

"""
不使用join
# 主线程调用子线程后直接结束,然后子线程再结束
main process end Fri Mar 23 17:34:01 2018 <_MainProcess(MainProcess, started)>
subprocess start Fri Mar 23 17:34:01 2018
subprocess end Fri Mar 23 17:34:04 2018
"""

"""
使用join
subprocess start Fri Mar 23 17:30:20 2018
subprocess end Fri Mar 23 17:30:23 2018
# 等待子进程完成后,结束主线程
main process end Fri Mar 23 17:30:23 2018 <_MainProcess(MainProcess, started)>
"""

 join用法考题

类似于单进程

from multiprocessing import Process
import time


def task(n, t):
    time.sleep(t)
    print('-------->%s' %n)

if __name__ == '__main__':
    p1=Process(target=task,args=(1,5))
    p2=Process(target=task,args=(2,2))
    p3=Process(target=task,args=(3,1))
    start = time.time()
    p1.start()
    p1.join()
    p2.start()
    p2.join()
    p3.start()
    p3.join()

    print('-------->time', time.time() - start)

------------------输出-----相当于单进程,时间等于3个进程执行时间的相加
-------->1
-------->2
-------->3
-------->time 9.534545183181763

类似于多进程 

from multiprocessing import Process
import time


def task(n, t):
    time.sleep(t)
    print('-------->%s' %n)

if __name__ == '__main__':
    p1=Process(target=task,args=(1,5))
    p2=Process(target=task,args=(2,2))
    p3=Process(target=task,args=(3,1))
    start = time.time()
    p_l = [p1,p2,p3]
    for p in p_l:
        p.start()

    for p in p_l:
        p.join()

    print('--------4 >time', time.time() - start)

---------------输出------------相当于多进程,执行时间等于最长进程的执行时间
-------->3
-------->2
-------->1
--------4 >time 5.624321699142456

  

 

使用多进程实现并发的服务器

服务器端

import socket
import multiprocessing
server = socket.socket()
server.bind(('127.0.0.1', 9988))
server.listen(5)

def read_msg(conn, addr):
    while True:
        try:
            data = conn.recv(1024)
            if data:  # 正常接收数据
                print('收到{}:数据{}'.format(addr,data.decode()))
                conn.send(data)
            else:  # 收到空消息,关闭
                print('close:{}'.format(addr))
                break
        except Exception as e:
            print(e)
            break
    conn.close()

if __name__ == '__main__':
    while True:
        print('-------主进程,等待连接------')
        conn, addr = server.accept()
        print('创建一个新的进程,和客户端{}通信'.format(addr))
        client= multiprocessing.Process(target=read_msg, args=(conn, addr))
        # client = threading.Thread(target=readable, args=((conn, addr)))
        # p.start()
        client.start()
    server.close()

客户端

# 客户端
import socket  # 导入socket模块

socket_client = socket.socket() # 创建监听套接字
socket_client.connect(('127.0.0.1', 9988))  # 连接套接字 ,要连接的IP与端口

while 1:
       cmd = input("Please input cmd:")   # 与人交互,输入命令
       if not cmd: continue
       elif cmd == 'q':break
       socket_client.send(cmd.encode('utf-8'))     # 把命令发送给服务端
       data = socket_client.recv(1024)
       print('recv',data)

socket_client.close()

 练习题

from multiprocessing import Process

n=100 #在windows系统中应该把全局变量定义在if __name__ == '__main__'之上就可以了

def work():
    global n
    n=0
    print('子进程内: ',n)


if __name__ == '__main__':
    p=Process(target=work)
    p.start()
    print('主进程内: ',n)

进程之间的内存空间是共享的还是隔离的?上述代码的执行结果是什么?
进程之间的内存空间是隔离的
执行结果:
主进程内:  100
子进程内:  0

改写下列程序,分别别实现下述打印效果

from multiprocessing import Process
import time
import random

def task(n):
    time.sleep(random.randint(1,3))
    print('-------->%s' %n)

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()

    print('-------->4')

效果一:保证最先输出-------->4

from multiprocessing import Process
import time
import random

def task(n):
    time.sleep(random.randint(1,3))
    print('-------->%s' %n)

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()

    print('-------->4')

----------输出
-------->4
-------->1
-------->3
-------->2

  

效果二:保证最后输出-------->4

from multiprocessing import Process
import time
import random

def task(n):
    time.sleep(random.randint(1,3))
    print('-------->%s' %n)

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('-------->4')
----------------------------输出
-------->1
-------->3
-------->2
-------->4

  

效果三:保证按顺序输出

from multiprocessing import Process
import time
import random

def task(n):
    time.sleep(random.randint(1,3))
    print('-------->%s' %n)

if __name__ == '__main__':
    p1=Process(target=task,args=(1,))
    p2=Process(target=task,args=(2,))
    p3=Process(target=task,args=(3,))

    p1.start()
    p1.join()
    p2.start()
    p2.join()
    p3.start()
    p3.join()


    print('-------->4')

-------------------------输出
-------->1
-------->2
-------->3
-------->4

2、判断上述三种效果,哪种属于并发,哪种属于串行?

第一种和第二种属于并发,最后一种属于并行

posted @ 2018-03-22 17:09  一只小小的寄居蟹  阅读(2056)  评论(0编辑  收藏  举报