Python程序中的进程操作--—--开启多进程

之前我们已经了解了很多进程相关的理论知识,了解进程是什么应该不再困难了,刚刚我们已经了解了,运行中的程序就是一个进程。所有的进程都是通过它的父进程来创建的。因此,运行起来的python程序也是一个进程,那么我们也可以在程序中再创建进程。多个进程可以实现并发效果,也就是说,当我们的程序中存在多个进程的时候,在某些时候,就会让程序的执行速度变快。以我们之前所学的知识,并不能实现创建进程这个功能,所以我们就需要借助python中强大的模块。

一、multiprocess模块

仔细说来,multiprocess不是一个模块而是python中一个操作、管理进程的包。 之所以叫multi是取自multiple的多功能的意思,在这个包中几乎包含了和进程有关的所有子模块。由于提供的子模块非常多,为了方便大家归类记忆,我将这部分大致分为四个部分:创建进程部分,进程同步部分,进程池部分,进程之间数据共享。

二、multiprocess中process模块

process模块是一个创建进程的模块,借助这个模块,就可以完成进程的创建。

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

强调:

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

参数介绍:

  • group参数未使用,值始终为None
  • target表示调用对象,即子进程要执行的任务
  • args表示调用对象的位置参数元组,args=(1,2,'randy',)
  • kwargs表示调用对象的字典,kwargs={'name':'randy','age':18}
  • name为子进程的名称

3.1 方法介绍

  • 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开启的进程

3.2 属性介绍

  • 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字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功(了解即可)

3.3 在windows中使用process模块注意事项

在Windows操作系统中由于没有fork(linux操作系统中创建进程的机制),在创建子进程的时候会自动 import 启动它的这个文件,而在 import 的时候又执行了整个文件。因此如果将process()直接写在文件中就会无限递归创建子进程报错。所以必须把创建子进程的部分使用if __name__ =='__main__' 判断保护起来,import 的时候,就不会递归运行了。

四、使用process模块创建进程

在一个python进程中开启子进程,start方法和并发效果。

4.1在python创建子进程方式一

import time
from multiprocessing import Process def f(name):
print("进程开始")
time.sleep(1) # 子进程进入堵塞状态,结束后,进入就绪状态,等待拿到cpu的使用权
print("进程结束")
time.sleep(1) """
创建进程这个print语句会执行两次, 原因是创建进程首先执行了当前程序的代码,则会执行一次
接着创建进程就是复制了一份代码,在子进程中还会在执行一次,所以就会执行打印两次
"""
print('进程测试') if __name__ == '__main__':
# args表示传递的参数
"""
创建一个进程,他会将主进程的代码复制一份到另外的一个程序,
而当前的主程序和子程序为异步状态,整个的程序会等待所有的主
进程和子进程运行完毕之后,才结束当前的程序
"""
p = Process(target=f, args=('bob',))
p.start()
time.sleep(1)
print('执行主进程的内容了')

进程测试

进程测试

进程开始2

进程结束2

主进程

4.2 在python中创建子进程方式二

from multiprocessing import Process
import time
class Task(Process):
def __init__(self, name):
# self.name = name # 这样赋值添加属性,在super()__init__时候有重新初始化了,所以要在init下面修改值 super().__init__()
self.name = name def run(self):
print(f"子进程的名称{self.name}")
time.sleep(0.03)
print("子进程结束") if __name__ == '__main__':
p = Task('randy') p.start() # 想操作系统, 发送开启子进程的请求
print("主进程")

主进程

子进程的名称randy

子进程结束

4.3 python中子进程和主进程的内存空间是隔离的

from multiprocessing import Process
import time x = 10 def task():
global x
print(f"子进程修改之前{x}")
x = 100
print(f"子进程修改之后x: {x}") if __name__ == '__main__':
p = Process(target=task)
p.start()
time.sleep(0.5)
print(f"全局x的值: {x}")

子进程修改之前10

子进程修改之后x: 100

全局x的值: 10

python中子进程和主进程的内存空间是隔离的

4.4 join方法使用

from multiprocessing import Process
import time
def task(x):
print(f"{x}进程开始") time.sleep(3)
print(f"{x}进程结束") """
创建进程这个print语句会执行两次, 原因是创建进程首先执行了当前程序的代码,则会执行一次
接着创建进程就是复制了一份代码,在子进程中还会在执行一次,所以就会执行打印两次
"""
print('进程测试') if __name__ == '__main__': p1 = Process(target=task, args=(1, ))
p1.start()
# join会阻塞住主进程在等待子进程结束,然后在执行join下面的代码(内部会调用wait)
p1.join()
print("主进程")
# p1 = Process(target=task, args=(1, ))
# p1.start()
# p2 = Process(target=task, args=(2, ))
# p2.start()
# p1.join()
# p2.join()

4.5 join多个进程时间统计

# 实现并行
from multiprocessing import Process
import time
def task(x):
print(f"{x}进程开始") time.sleep(x)
print(f"{x}进程结束") """
创建进程这个print语句会执行两次, 原因是创建进程首先执行了当前程序的代码,则会执行一次
接着创建进程就是复制了一份代码,在子进程中还会在执行一次,所以就会执行打印两次
"""
print('进程测试') if __name__ == '__main__': p1 = Process(target=task, args=(1, )) p2 = Process(target=task, args=(2, )) p3 = Process(target=task, args=(3, )) # 开始时间
start = time.time()
p1.start()
p2.start()
p3.start() # join会阻塞住主进程在等待子进程结束,然后在执行join下面的代码(内部会调用wait)
p1.join()
p2.join()
p3.join() end = time.time() """
程序运行的时间为3s多,主要是因为创建的三个子进程会同时启动
会以时间最长的进程为基准,
"""
print("程序运行时间%s" %(end-start)) # 程序运行时间3.5375335216522217 # 实现串行
from multiprocessing import Process
import time
def task(x):
print(f"{x}进程开始") time.sleep(x)
print(f"{x}进程结束") """
创建进程这个print语句会执行两次, 原因是创建进程首先执行了当前程序的代码,则会执行一次
接着创建进程就是复制了一份代码,在子进程中还会在执行一次,所以就会执行打印两次
"""
print('进程测试') if __name__ == '__main__': p1 = Process(target=task, args=(1, ))
p2 = Process(target=task, args=(2, ))
p3 = Process(target=task, args=(3, )) # 开始时间
start = time.time()
# 实现串行,线程会一个一个的执行线程,一个线程执行完之后才会执行下一个线程
p1.start()
p1.join() p2.start()
p2.join() p3.start()
p3.join() end = time.time() """
程序运行的时间为6s多,主要是因为创建的三个子进程会同时启动
会以时间最长的进程为基准,
"""
print("程序运行时间%s" %(end-start)) # 程序运行时间7.236638784408569

程序运行时间3.5375335216522217

程序运行时间7.236638784408569

#详细解析如下:
#进程只要start就会在开始运行了,所以p1-p4.start()时,系统中已经有四个并发的进程了
#而我们p1.join()是在等p1结束,没错p1只要不结束主线程就会一直卡在原地,这也是问题的关键
#join是让主线程等,而p1-p4仍然是并发执行的,p1.join的时候,其余p2,p3,p4仍然在运行,等#p1.join结束,可能p2,p3,p4早已经结束了,这样p2.join,p3.join.p4.join直接通过检测,无需等待
# 所以4个join花费的总时间仍然是耗费时间最长的那个进程运行的时间

4.6 多个进程同时运行

from multiprocessing import Process
import time
def task(x):
print(f"{x}进程开始") time.sleep(x)
print(f"{x}进程结束") print('进程测试') if __name__ == '__main__':
start = time.time()
p_list = []
# 创建并启动线程
for i in range(1,5):
p = Process(target=task, args=(i, ))
p.start()
p_list.append(p) # 使用join方法
for p in p_list:
p.join()
end = time.time()
print("程序运行时间%s" %(end-start))

4.7 查看主进程和子进程的进程号

from multiprocessing import Process,current_process
import time
import os
def task():
print("进程开始")
time.sleep(0.2)
# 在子进程查看自己的pid
print(f'在子进程中查看自己的pid: {current_process().pid}')
print(f'在子进程中查看自己的pid: {os.getpid()}')
# 在子进程中查看父进程pid
print(f'在子进程中查看父进程pid: {os.getppid()}')
print("进程结束")
if __name__ == '__main__':
p = Process(target=task)
p.start() print(f"在主进程中查看子进程的pid:{p.pid}")
print(f'主进程的pid: {os.getpid()}') print(f'主进程中父进程pid: {os.getppid()}') """
在window中的进程创建查看pid号他的顺序是从小到大排序,主线程pid大于子线程的pid
os.getpid() 获取当前进程的pid
os.getppid() 获取当前进程的父进程
子进程对象.pid 获取当前进程的子进程的pid
"""

进阶,多个进程同时运行(注意,子进程的执行顺序不是根据启动顺序决定的)

4.8 process中常用的属性

from multiprocessing import Process,current_process
import time
import os
def task():
print("进程开始") time.sleep(0.2) # 在子进程查看自己的pid
print(f'在子进程中查看自己的pid: {current_process().pid}') print("进程结束")
if __name__ == '__main__':
p = Process(target=task)
p.start()
# 1 查看进程的名称
print(p.name)
# 2 判断进程是否还存在
print(p.is_alive())
time.sleep(3)
print(p.is_alive()) # 3 告诉操作系统结束之后关闭所有进程
p2 = Process(target=task)
p2.start()
p2.terminate() print("terminate: ", p2.is_alive())
p2.join()
print("terminate: ", p2.is_alive())

五、守护进程

会随着主进程的结束而结束。

主进程创建守护进程

  其一:守护进程会在主进程代码执行结束后就终止

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

注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止。

5.1 守护进程的启动

import os
import time
from multiprocessing import Process class Myprocess(Process):
def __init__(self,person):
super().__init__()
self.person = person
def run(self):
print(os.getpid(),self.name)
print('%s正在和女主播聊天' %self.person) p=Myprocess('哪吒')
p.daemon=True # 一定要在p.start()前设置,设置p为守护进程,守护进程中禁止p创建子进程,并且父进程代码执行结束,p即终止运行
p.start()
time.sleep(10) # 在sleep时查看进程id对应的进程ps -ef|grep id
print('主')

5.2主进程代码执行结束守护进程立即结束

from multiprocessing import Process

def foo():
print(123)
time.sleep(1)
print("end123") def bar():
print(456)
time.sleep(3)
print("end456") p1=Process(target=foo)
p2=Process(target=bar) p1.daemon=True
p1.start()
p2.start()
time.sleep(0.1)
print("main-------") # 打印该行则主进程代码结束,则守护进程p1应该被终止.#可能会有p1任务执行的打印信息123,因为主进程打印main----时,p1也执行了,但是随即被终止

六、socket聊天并发实例

6.1 使用多进程是新socket聊天并发-server端

from socket import *
from multiprocessing import Process server=socket(AF_INET,SOCK_STREAM)
server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
server.bind(('127.0.0.1',8080))
server.listen(5) def talk(conn,client_addr):
while True:
try:
# 注意在这里不能使用input进行交互信息,因为是在子进程中输入的,所以你输入不对
msg=conn.recv(1024)
if not msg:break
conn.send(msg.upper())
except Exception:
break if __name__ == '__main__': # windows下start进程一定要写到这下面
while True:
conn,client_addr=server.accept()
p=Process(target=talk,args=(conn,client_addr))
p.start()

6.1 使用多进程是新socket聊天并发-client端

import socket
client = socket.socket() client.connect(("127.0.0.1", 8888)) while True:
msg = input("请输入信息")
if msg == 'q':
break client.send(msg.encode('utf-8'))
data = client.recv(1024)
print(data)
import socket
client = socket.socket() client.connect(("127.0.0.1", 8888)) while True:
msg = input("请输入信息")
if msg == 'q':
break client.send(msg.encode('utf-8'))
data = client.recv(1024)
print(data)

Python程序中的进程操作--—--开启多进程的更多相关文章

  1. Python程序中的进程操作-开启多进程(multiprocess.process)

    目录 一.multiprocess模块 二.multiprocess.process模块 三.process模块介绍 3.1 方法介绍 3.2 属性介绍 3.3 在windows中使用process模 ...

  2. 第十五章、python中的进程操作-开启多进程

    目录 第十五章.python中的进程操作-开启多进程 一.multprocess模块 二.multprocess.process模块 三.Process()对象方法介绍 四.Process()对象属性 ...

  3. 在Python程序中的进程操作,multiprocess.Process模块

    在python程序中的进程操作 之前我们已经了解了很多进程相关的理论知识,了解进程是什么应该不再困难了,刚刚我们已经了解了,运行中的程序就是一个进程.所有的进程都是通过它的父进程来创建的.因此,运行起 ...

  4. python 全栈开发,Day38(在python程序中的进程操作,multiprocess.Process模块)

    昨日内容回顾 操作系统纸带打孔计算机批处理 —— 磁带 联机 脱机多道操作系统 —— 极大的提高了CPU的利用率 在计算机中 可以有超过一个进程 进程遇到IO的时候 切换给另外的进程使用CPU 数据隔 ...

  5. Python程序中的进程操作

    之前我们已经了解了很多进程相关的理论知识,了解进程是什么应该不再困难了,刚刚我们已经了解了,运行中的程序就是一个进程.所有的进程都是通过它的父进程来创建的.因此,运行起来的python程序也是一个进程 ...

  6. Python程序中的进程操作-进程池(multiprocess.Pool)

    目录 一.进程池 二.概念介绍--multiprocess.Pool 三.参数用法 四.主要方法 五.其他方法(了解) 六.代码实例--multiprocess.Pool 6.1 同步 6.2 异步 ...

  7. 29、Python程序中的进程操作(multiprocess.process)

    一.multiprocess模块 multiprocess不是一个模块而是python中一个操作.管理进程的包. 子模块分为四个部分: 创建进程部分 进程同步部分 进程池部分 进程之间数据共享 二.m ...

  8. 在python程序中的进程操作

    multiprocess模块 multiprocess不是一个模块而是python中一个操作.管理进程的包. 之所以叫multi是取自multiple的多功能的意思,在这个包中几乎包含了和进程有关的所 ...

  9. Python程序中的进程操作-进程间通信(multiprocess.Queue)

    目录 一.进程间通信 二.队列 2.1 概念介绍--multiprocess.Queue 2.1.1 方法介绍 2.1.2 其他方法(了解) 三.代码实例--multiprocess.Queue 3. ...

随机推荐

  1. 【LeetCode】160. 相交链表

    题目 输入两个链表,找出它们的第一个公共节点. 如下面的两个链表: 在节点 c1 开始相交. 示例 1: 输入:intersectVal = 8, listA = [4,1,8,4,5], listB ...

  2. 解决Tomcat在idea控制台乱码问题

    解决Tomcat乱码问题 打开Tomcat安装目录:apache-tomcat-9.0.14-windows-x64/conf/logging.properties 大概在50多行注释这一句#java ...

  3. 执行 composer update 命令的时候报 Your requirements could not be resolved to an installable set of packages. 错误

    Your requirements could not be resolved to an installable set of packages. 以上原因:不匹配composer.json要求的版 ...

  4. kettle将csv文件导入数据库

    具体过程学习了: 1.连接数据库 2.添加新资源库 3.选择Other Repositories 4.选择Database Repository,第二个需要配置额外参数 5.连接数据库相关设置 6.连 ...

  5. win10安装centOS 失去win启动项

    联网:执行以下三条命令 yum -y install epel-release yum -y install ntfs-3g grub2-mkconfig -o /boot/grub2/grub.cf ...

  6. npm、yarn 简单使用记录

    npm.yarn常用命令记录,后续会陆续补充... 经过使用发现yarn再下包是速度快,所以日常以yarn指令应用为主 npm查看仓库地址:npm config get registrynpm设置淘宝 ...

  7. OC Swift混编-Swift.h File not found

    https://www.jianshu.com/p/f860fe1718ca 2016.09.13 11:53* 字数 266 阅读 1935评论 1喜欢 1 今天碰到个神坑,本人项目是OC项目,最近 ...

  8. javascript数组日期

    arr forEach(callback,thisArg) thisArg:指明回调函数的this指向 callback(element,index,arr) element:每次取到的数组元素值 i ...

  9. 吴裕雄--天生自然Django框架开发笔记:Django 安装

    Window 下安装 Django 如果你还未安装Python环境需要先下载Python安装包. 1.Python 下载地址:https://www.python.org/downloads/ 2.D ...

  10. GTK入门

    环境准备 官网下载 GTK 源码包,因为本机 GLib 版本不够,下载一个非最新版的 GTK3.8.0 先学习用 直接阅读 "/gtk+-3.8.0/docs/reference/gtk/h ...