IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> Python编程 | 系统编程 | 并行系统工具 | 进程分支 -> 正文阅读

[Python知识库]Python编程 | 系统编程 | 并行系统工具 | 进程分支

进程分支

分支的想法基于程序复制:当调用分支例行程序时,操作系统会创建该程序及其内存中的进程的副本,然后开始与原有程序并行的运行该副本。

分支操作后,原来的程序副本成为父进程,而由os.fork创建的副本称为子进程,子进程在父进程结束后还可以继续运行

示例:fork_1.py

#!/usr/bin/env python

"分支出子进程,直到你输入“q”"


import os


def child():
	"子进程"

	print('Hello from child! pid ->', os.getpid())


def parent():
	"父进程"

	while True:
		new_pid_int = os.fork()

		if new_pid_int == 0:
			child()
			os._exit(0)	# 否则回到父循环中
		else:
			print('Hello from parent! parent_pid ->', os.getpid(),
				'child_pid ->', new_pid_int)

		if input() == 'q':
			break


if __name__ == '__main__':
	parent()

输出:

Hello from parent! parent_pid -> 19850 child_pid -> 19851
Hello from child! pid -> 19851

Hello from parent! parent_pid -> 19850 child_pid -> 19857
Hello from child! pid -> 19857

Hello from parent! parent_pid -> 19850 child_pid -> 19858
Hello from child! pid -> 19858
q
  • os.fork函数为调用程序创建了一个副本,所以它为每份副本返回不同的值:在子进程中返回0,在父进程中返回新子进程的ID

  • 为了只在父进程下创建不同的进程,程序一般会对返回结果进行检验:比如这个脚本,只在子进程中运行child函数。

  • child进程函数也显示地用os._exit(0)来退出。如果不调用它,子进程将在child函数返回后延续(记住它只是原来进程的一个副本)。最后的结果是子进程将回到父进程的循环里,然后分支它自己的子进程。如果你删除那个退出调用再运行一遍,可能得多次输入“q”来停止程序。

父进程 子进程 os.fork() os._exit(0) 父进程 子进程

为了更好地体现多个分支进程并行运行,让我们来做一点复杂点儿的操作:

示例:fork_count.py

#!/usr/bin/env python


"""
分支进程基本操作:本程序启用了5个副本,与原有程序并行运行;每个副本在一个标准输入/输出流上重复5次。
"""


import os
import time


def counter(count_int):
	"子进程"

	for i_int in range(count_int + 1):
		time.sleep(1)
		print('\n{pid_int} -> {i_int}'.format(pid_int=os.getpid(), i_int=i_int))


if __name__ == '__main__':
	for i_int in range(5):
		pid_int = os.fork()

		if pid_int != 0:
			print('Process {pid_int} spawned'.format(pid_int=pid_int))
		else:
			counter(5)
			os._exit(0)

	print('Main process exiting.')

输出:

Process 26409 spawned
Process 26410 spawned
Process 26411 spawned
Process 26412 spawned
Process 26413 spawned
Main process exiting.

26409 -> 0

26410 -> 0

26411 -> 0

26412 -> 0

26413 -> 0

26409 -> 1

26410 -> 1

26411 -> 1

26412 -> 1

26413 -> 1

26409 -> 2
26411 -> 2


26410 -> 2

26413 -> 2

26412 -> 2

26411 -> 3

26409 -> 3

26410 -> 3

26412 -> 3

26413 -> 3

26411 -> 4

26409 -> 4

26410 -> 4
26413 -> 4


26412 -> 4

26411 -> 5

26409 -> 5

26412 -> 5
26410 -> 5


26413 -> 5

  • 所有这些进程的输出结果在同一个屏幕上显示,因为它们都共享标准输出流。从技术层面来说,分支进程得到原有进程的全局内存中内容的副本,包括所打开文件的描述符;如果某个子进程改变了某个全局对象,那它只是改变了自己的副本。

forkexec的组合

在类Unix平台下,分支通常是启动独立运行的程序的基础,这些独立程序与执行fork调用的程序截然不同。

示例:fork_exec.py

#!/usr/bin/env python


"运行程序,直到你输入“q”"


def main():
	import os


	parm_int = 0

	while True:
		parm_int += 1
		pid_int = os.fork()

		if not pid_int:
			os.execlp('python', 'python', 'child.py', str(parm_int))		# 覆盖原来的程序
			assert False, 'Error starting program'							# 不应该返回,因为原程序已被覆盖为child.py
		else:
			print('Child is', pid_int)
			if input() == 'q':
				break


if __name__ == '__main__':
	main()
  • os.execlp调用可以用一个全新的程序代替即执行覆盖当前进程中正在运行的程序,因此os.execlp调用不会返回。如果调用返回,则表示发生了错误,因此我们在后面编写了一句assert语句,以便抛出异常。

os.exec调用格式

os.exec共有8种变体:

  • os.execv(program, commandlinesequence):基本的“v”执行形式,需要传入可执行程序的名称,以及用来运行程序的命令行参数字符串组成(即你在shell中起始程序通常输入的语句)的列表或元组。
  • os.execl(program, cmdarg1, cmdarg2, ... cmdargN):基本的“l”执行形式,需要传入可执行程序的名称,以及一个或多个以单个的函数参数形式传入的命令行参数,相当于运行os.execv(program, (cmdarg1, cmdarg2, ... cmdargN))
  • os.execlpos.execvp:加上字母“p”表示Python将使用你的系统搜索路径设置(即PATH)来定位可执行程序的目录。
  • os.execleos.execve:加上字母“e”表示将在最后添加一个参数,这个参数是一个字典,包含将发送给程序的shell环境变量。
  • os.execlpeos.execvpe:加上字母“p”、“e”表示使用搜索路径并且接受shell环境变量字典参数。

派生子程序

示例:child.py

#!/usr/bin/env python


import os
import sys


print('Hello from child!', os.getpid(), sys.argv[1])

输出:fork_exec.py

Child is 19999
Hello from child! 19999 1

Child is 20000
Hello from child! 20000 2

Child is 20006
Hello from child! 20006 3
q

😃 学完博客后,是不是有所启发呢?如果对此还有疑问,欢迎在评论区留言哦。
如果还想了解更多的信息,欢迎大佬们关注我哦,也可以查看我的个人博客网站BeacherHou

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2021-08-05 17:18:30  更:2021-08-05 17:19:05 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 13:19:09-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码