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、判断上述三种效果,哪种属于并发,哪种属于串行?

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

Python进程-实现的更多相关文章

  1. python——进程基础

    我们现在都知道python的多线程是个坑了,那么多进程在这个时候就变得很必要了.多进程实现了多CPU的利用,效率简直棒棒哒~~~ 拥有一个多进程程序: #!/usr/bin/env python #- ...

  2. 使用gdb调试Python进程

    使用gdb调试Python进程 有时我们会想调试一个正在运行的Python进程,或者一个Python进程的coredump.例如现在遇到一个mod_wsgi的进程僵死了,不接受请求,想看看究竟是运行到 ...

  3. python进程、线程、协程(转载)

    python 线程与进程简介 进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资 ...

  4. Python进程、线程、协程详解

    进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资源的管理和分配.任务的调度. ...

  5. python进程池剖析(一)

    python中两个常用来处理进程的模块分别是subprocess和multiprocessing,其中subprocess通常用于执行外部程序,比如一些第三方应用程序,而不是Python程序.如果需要 ...

  6. python——进程、线程、协程

    Python线程 Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #!/usr/bin/env pytho ...

  7. python/进程线程的总结

    python/进程线程的总结 一.进程和线程的描述: 进程:最小的资源管理单位 线程:最小的执行单位 执行一个进程时就默认执行一个线程(主线程) 进程和线程的工作方式: 串行: 假如共有A.B.C任务 ...

  8. python 进程介绍 进程简单使用 join 验证空间隔离

    一.多道程序设计技术(详情参考:https://www.cnblogs.com/clschao/articles/9613464.html) 所谓多道程序设计技术,就是指允许多个程序同时进入内存并运行 ...

  9. Python 进程之间共享数据

    最近遇到多进程共享数据的问题,到网上查了有几篇博客写的蛮好的,记录下来方便以后查看. 一.Python multiprocessing 跨进程对象共享  在mp库当中,跨进程对象共享有三种方式,第一种 ...

  10. python进程、多进程

    进程: 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.在早期面向进程设计的计算机结构中,进程是程序的基本执行实体:在当 ...

随机推荐

  1. hihoCoder 1051 : 补提交卡 枚举

    思路:预处理cnt(i)表示前i个数中有多少天需要补提交卡,枚举各个连续区间,区间[j, i]中需要补提交卡的天数是cnt(i) - cnt(j-1),判断m是否大于等于cnt(i) - cnt(j- ...

  2. 设置TCP_USER_TIMEOUT参数来判断tcp连接是否断开

    [TOC] 1. bug描述 前段时间遇到这样的一个问题,openstack一个控制节点宕机后,在宕机后一段时间内创建的虚拟机,一直卡在创建中的状态.有的甚至要等到16分钟之后虚拟机才会切换到下一个状 ...

  3. mysql 主从同步 mysql代理服务器

    搭建mysql主从同步(实现数据自动备份)实例:把主机192.168.4.100的数据库配置为主机192.168.4.99的从数据库 主数据库服务器配置修改配置文件: [root@mysql ~]# ...

  4. freemarker写select组件(五)

    freemarker写select组件 1.宏定义 <#macro select id datas value="" key="" text=" ...

  5. freemarker写select组件(二)

    freemarker写select组件 1.宏定义 <#macro select id datas value=""> <select id="${id ...

  6. 动态链接库(DLL)

    DLL 的类型 当您在应用程序中加载 DLL 时,可以使用两种链接方法来调用导出的 DLL 函数.这两种链接方法是加载时动态链接和运行时动态链接. 加载时动态链接 在加载时动态链接中,应用程序像调用本 ...

  7. C#技术点--修改系统时间

    C#的System.DateTime类提供了对日期时间的封装,用它进行时间的转换和处理很方便,但是我没有在其中找到任何可以用来修改系统时间的成员.用过VC.VB等的朋友可能知道,我们可以调用Win32 ...

  8. Xshell配色为ubuntu风格

    背景 为了远程连接服务器,用Xshell作为连接工具,因为好(mian)用(fei),服务器是ubuntu的,因此看不习惯Xshell自带的黑白色,下面给出了ubuntu的配色方案,使用的时候直接导入 ...

  9. RobotFramework下的http接口自动化Get Response Status 关键字的使用

    Get Response Status 关键字用来获取http请求返回的http状态码. 示例1:访问苏宁易购网站上的http推荐接口,使用Get Response Status 关键字来获取返回的h ...

  10. Ubantu16.04进行Android 8.0源码编译

    参考这篇博客 经过测试,8.0源码下载及编译之后,占用100多G的硬盘空间,尽量给ubantu系统多留一些硬盘空间,如果后续需要在编译好的源码上进行开发,需要预留更多的控件,为了防止后续出现文件权限问 ...