您好!欢迎来到爱源码

爱源码

热门搜索: 抖音快手短视频下载   

Python-26简明教程,Python多进程编程 《php源码》

  • 时间:2022-07-13 01:36 编辑: 来源: 阅读:311
  • 扫一扫,手机访问
摘要:Python-26简明教程,Python多进程编程 《php源码》
学习编程最有效的方法就是手敲代码。 1.什么是多重处理?我们写的Python代码是一个程序,Python程序是由Python解释器执行的。 程序是存储在磁盘上的文件。Python程序需要通过Python解释器把它读入内存,然后解释并执行它。 处于执行(运行)状态的程序称为进程。 进程只能通过操作系统分配资源和调度来执行。 系统将为每个流程分配一个流程ID(非负整数),作为流程的唯一标识。 现代操作系统提供了多进程同步执行的机制,即操作系统允许多个进程同时运行。 操作系统负责进程管理。 比如我们在一边听音乐一边解word文档,这就需要一个word程序和一个音乐软件同时运行。 多进程机制的硬件支持由CPU提供,分为单核和多核。 单核CPU只有一个核,同一时间只能执行一个进程。单核CPU上多个进程的执行实际上是并发的。 背后的原理是CPU运行速度非常快。多进程执行实际上是在每个进程的间隔时间运行的,间隔时间短到人类无法察觉这个间隔时间。这样,人类就感觉多个进程在同时执行。 多核CPU有多个核,每个核可以解决进程,这样每个进程可以运行在不同的CPU上。这叫并行执行,真的是同时运行。 2.fork函数Python语言还支持多进程编程,以支持更复杂的高性能应用。 为了支持多进程编程,操作系统提供了最原始的系统调用fork()函数,使得当前进程可以创建一个子进程,这样父进程和子进程就可以解决不同的事务。 Python中的fork()函数封装在os模块中。这个函数的原型非常简单,没有任何参数,如下:fork()与一般函数的不同之处在于,这个函数的返回值是特殊的。fork函数执行一次,返回两个值:返回值为0:是子进程范围,子进程可以通过getppid()函数获取父进程ID。返回值是子进程id:是父进程范围,这样parent/usr/bin/env python 3 import OS #这里是父进程#创建子进程pid = os.fork()如果pid == 0: #子进程的作用域,并写出子进程需要解决的事务打印('这里是子进程,父进程id是:%s,子进程ID是:%s'% (os.getppID(),os.getpID())否则:#父进程作用域, 编写父进程需要解决的事务打印('这里是父进程,父进程id是:% s,子进程id是:%s'% (os.getpid()),Pid)#父进程和子进程都会执行这里的打印('进程ID:%s'% os.getpid())。 在上面的代码中,我们调用了fork()函数,返回值为PID:当pid:pid 0:进入子进程的作用域。我们用getppid()函数获取父进程id,用Getpid()函数获取当前进程(子进程)的ID。当pid不为0时:进入父进程的范围,则Pid是子进程ID。我们使用getpid()函数获取当前进程(父进程)id代码的最后一行,print ('process ID:%s'% os.getpid()),父进程和子进程都将执行到 这段代码的执行结果如下:$ python3 Test.py这里是父进程,父进程ID是:1405,子进程ID是:1406 #这里最后一行代码的输出是子进程,父进程ID是:1405,子进程ID是:1406: 1406 #最后一行代码的输出是上面的执行结果,并且 之所以最后一行代码,子进程和父进程都能执行,是因为fork()函数执行后,后续代码同时存在于两个进程(父进程和子进程)的空间中。 返回值pid为0时,为子进程空间;当返回值pid不为0时,为父进程空间。 而最后一行代码,属于pid == 0的范围,也属于else的范围,所以父子进程会执行这段代码。 3.孤儿进程和僵尸进程我们已经知道,fork()函数之后,会出现两个进程,分别是父进程和子进程。 这两个进程中哪一个会先执行?是父进程先于子进程执行,还是子进程先于父进程执行?答案是不确定的。 因为先执行哪个父子进程不是由程序决定的,而是由操作系统的调度决定的。操作系统先调度谁,谁就先执行。 另外,当父子进程退出时,也会因为退出顺序的不同而造成孤儿进程和僵尸进程:孤儿进程:父进程先于子进程退出,子进程会成为孤儿进程。 孤儿进程将由系统进程接管,系统进程将成为孤儿进程的父进程。 当孤儿进程存在时,系统进程会解决它。 僵尸进程:如果子进程退出时父进程未能解决子进程的退出状态,则该进程退出后所占用的系统资源不会被释放,即该进程不正常工作,但仍占用系统资源。这样的过程叫做僵尸过程。 我们来写一个会产生僵尸进程的代码:#!/usr/bin/envpython3import OS导入时间#这里是父进程#创建子进程pid = os.fork()如果pid == 0: #子进程的作用域,并写出子进程需要求解的事务打印('这里是子进程,父进程id是:%s,子进程id是:%s'% (os.getppID(),os.getpID())否则:#父进程作用域,写出父进程需要求解的事务打印('这里是父进程, 父进程id为:% s,子进程id为:% s“%(OS . getpid()),Pid)) print('父进程正在休眠600秒...' )time.sleep (600) #父进程和子进程都将在这里执行。在上面的代码print ('process ID:%s'% os.getpid())中,我们在父进程中休眠600秒,这样子进程将在父进程和父进程之前退出 我们用python3来执行这个程序,如下:$ python3 Test.py这里是父进程,父进程ID是:1524,子进程ID是:1525...这里是子进程,父进程ID是:1524,子进程ID是:1525进程ID: 1525 `注意,这里父进程处于睡眠状态,而 然后,我们使用ps命令查看当前python3进程,如下:$ PS-AUX | Grep Python 31 2 3 4 5 6 7 8 9 10 11wp 1524 1.0 0 23992 6604 pts/2 ` s `。09:13 0:00 python 3 test . pywp 1525 0.0 0.0 0 0 pts/2 ` z ` 09:13 0:00[python 3]& lt;已不存在的& gt(为了方便查看,我在上面的输出中添加了列数,共有11列。 第二列是进程ID,第八列是进程状态。 我们看到父进程(1524)处于S状态(即休眠状态),子进程(1525)处于Z状态(即僵尸状态) 这说明子进程先于父进程退出,父进程没有解决子进程的退出状态,所以子进程变成了僵尸进程。 4.避免僵尸进程。孤儿进程不会造成任何伤害,而僵尸进程会造成系统资源的浪费,所以要避免僵尸进程。 既然僵尸进程会导致资源的浪费,为什么操作系统还要设计僵尸进程的存在呢?僵尸进程存在的意义是在进程退出时保存少量信息,如进程ID、终止状态、资源使用情况等。,可通过其父进程获得适当的解决方案。 所以子进程退出后,只能通过父进程的解决方案来避免僵尸进程。 等待函数父进程可以通过wait()函数获取子进程的退出状态。 应该注意,调用wait()函数的进程将一直阻塞,直到它的一个子进程退出。 wait函数的原型如下:wait()`该函数返回一个tuple (PID,status)。PID是退出进程的IDstatus,退出进程的状态`父进程调用wait()函数有两种情况。这两种情况都可以正确避免僵尸进程:父进程在子进程退出前调用wait(),父进程在子进程退出后调用wait()。我们分别演示这两种情况的代码,通过sleep函数控制哪个进程先退出:父进程在子进程退出之前调用wait()代码:#!/usr/bin/envpython3import OS导入时间#这里是父进程#创建子进程pid = os.fork()如果pid == 0: #子进程调用sleep确保父进程调用wait print first('这里是子进程,父进程pid:%s,子进程PID:% s sleep 5s'% (OS。Getppid(),OS。GetPID())时间。Sleep (5) Else: #父进程调用wait,块在这里child_pid,Child_status = os.wait() print('这里是父进程,父进程pid:%s,子进程pid:%s,子进程退出状态:%s'% (os.getpid(),child_pid,Child_status)) print('父进程休眠600秒,此时用ps命令检查进程状态')time.sleep(600)这段代码的执行结果如下:$ python3 Test.py这里是子进程,即 子进程pid:1586睡眠5秒这里是父进程,父进程pid:1585,子进程pid:1586,子进程退出状态:0父进程睡眠600秒,然后用ps命令检查进程状态。 当父进程睡眠600秒被打印出来,然后使用ps命令检查进程状态,确认子进程已经退出。我们使用ps命令来检查python3进程状态,如下:$ PS-aux | grep python 31 2 3 4 5 6 7 8 9 10 11wp 1585 0.0 0 23992 6604 pts/2s 10:10 0:00 python 3 test . py可以看出,此时只有父进程是活动的,子进程已经成功退出,并不处于僵尸进程状态。 父进程在子进程退出后调用wait()代码:#!/usr/bin/envpython3import OS导入时间#这里是父进程#创建子进程pid = os.fork()如果pid == 0: #子进程范围print('这里是子进程,父进程pid:%s,子进程PID:% s'% (OS.getppid(),OS.getpid())否则:#父进程应该先休眠,这样子进程可以先退出,然后调用wait time.sleep(5) child_pid,Child_status = os.wait() print('这里是父进程,父进程 子进程退出状态:%s'% (os.getpid(),child_pid,Child_status)) print('父进程休眠600秒,然后用ps命令检查进程状态')time.sleep(600)代码执行结果如下:$ python3 Test.py这里是子进程,父进程pid:1591,子进程pid:1592这里是父进程,父进程pid:1591,子进程pid:1592,子进程退出状态:0父进程休眠600秒 此时,使用ps命令检查进程状态。当父进程睡眠600秒被打印出来,用ps命令检查进程状态,我们用ps命令检查python3进程状态。执行结果如下:$ PS-aux | grep Python 31 2 3 4 5 6 7 8 9 10 11wp 1591 0.2 0.0 23992 6620 pts/2s 10:20 0:00 Python 3 test . py可以看出此时只有父进程是活动的,子进程已经成功退出,不处于僵尸进程状态。 5.用信号解决僵尸进程因为wait()函数会阻塞调用进程,会让调用进程无法解决其他事情。 其实这是不正当的,因为浪费了一个过程。 我们可以用信号来解决这种情况。 信号是一种系统中断。当一个进程遇到系统中断时,会中断该进程正在执行的正常进程,转而求解中断函数。 进程解决中断函数后,会返回到进程的原解决进程。 中断功能是客户向系统注册的一个功能,用来解决遇到信号时的问题。 因为子进程在退出时会向父进程发送SIGCHLD信号,父进程可以通过捕获这个信号来解决子进程。 Linux系统中的信号模块,我们可以通过kill -l命令查看系统中的信号, 共有64个信号:$ kill-l 1)sighup 2)sigint 3)SIG quit 4)sigill 5)SIG trap 6)SIG abrt 7)SIG bus 8)sigfpe 9)sigkill 10)sigusr 111)sigsegv 12)sigusr 2 13)SIG pipe 14)sigal RM 15)sigterm 16)SIGSTKFLT 17)SIGCHLD 18)SIG cont 19)SIGSTOP 20)sigt tin 21)SIGTTOU 23)SIGURG 23) SIGRTMIN+11 46)SIGRTMIN+12 47)SIGRTMIN+1348)SIGRTMIN+14 49)SIGRTMIN+15 50)SIGRTMAX-14 51)SIGRTMAX-13 52)SIGRTMAX-11 54)SIGRTMAX-10 55)SIGRTMAX-9 56)SIGRTMAX-8 57)SIGRTMAX-758)SIGRTMAX-6 59) 让我们通过dir(signal)检查一下信号模块的内容:> & gt& gtdir(signal)['Handlers ',' ITIMER_PROF ',' ITIMER_REAL ',' ITIMER_VIRTUAL ',' ITIMER _ error ',' NSIG ',' SIGABRT ',' SIGALRM ',' SIGBUS ',' SIGCHLD ',' SIGCLD ',' SIGCONT ',' SIGFPE ',' SIGHUP ',' SIGILL ',' SIGINT ',' SIGIO ',' SIGIOT ',' SIGKILL ',' SIGPIPE ',' SIGPOLL ',' SIGPROF ',' SIGPWR ',' SIGQUIT ',' SIGRTMAX ',' SIGRTMIN ',' SIG 为了求解信号,信号模块中的信号函数需要向系统注册,要捕获哪个信号,以及求解信号的函数。 signal函数的原型如下:signal(signalnum,handler)这个函数接收两个参数,signalnum和handlersignalnum是要捕获的信号。handler是信号解析函数。handler参数有三个值:SIG_DFL:系统设置的默认值。SIG_IGN:表示信号被忽略的函数类型参数。该函数接收两个参数,即信号号和当前堆栈帧。接下来,我们编写代码,用信号解决僵尸进程。 例如:#!/usr/bin/envpython3import OS导入时间导入信号#这里是父进程#信号解析函数#这个函数必须有两个参数def sig_handelr(signum,Frame): # print(frame) #调用父进程中的wait来求解子进程child _ PID,child _ status = os.wait () print('这里是父进程,它收到了信号:%s,然后用ps命令检查进程状态。 父进程pid:%s,子进程pid:%s,子进程退出状态:% s'% (signum,OS。GetPID(),child _ PID,child _ status)) #父进程寄存器信号解析函数signal.signal(signal。SIGCHLD,Sig_handelr)# Create子进程pid = os.fork()if pid == 0: #子进程范围print('这里是子进程,父进程pid:%s,子进程pid:%s,子进程休眠10秒' % (os.getppid(),Os.getpid ()) #让子进程先休眠10秒,然后退出time.sleep(10)else: print('这里是父进程,父进程休眠600秒,所以子进程保证先退出')time . 执行结果如下:$ python3 Test.py这里是父进程,父进程休眠600秒,保证子进程先退出。下面是子进程,父进程pid:1651,子进程pid:1652,子进程休眠10秒。这里是父进程,它接收信号:17。此时,使用ps命令检查进程状态。 父进程pid:1651,子进程pid:1652,子进程退出状态:0 '这里程序没有退出,因为父进程等待子进程sleep 10 600秒10秒。退出后我们用ps命令检查进程状态:ps-aux | grep Python 31 2 3 4 5 6 7 8 9 10 11wp 1651 0.0 0 23992 6708 pts/S21:38 0:00 Python 3 test . py通过PS命令可以看到子进程退出后并没有变成僵尸进程,说明我们的解决方案没有问题。 6.忽略SIGCHLD信号的一个更简单的解决方案是直接忽略SIGCHLD信号,而不注册该信号的解函数。 忽略信号也是解决信号的一种方式,同样不会把子进程变成僵尸进程。 代码如下:#!/usr/bin/envpython3import OS导入时间导入信号#这里是父进程#父进程注册信号。解决方法是忽略signal.signal(信号。西格德,发信号。SIG_IGN)# Create子进程pid = os.fork()if pid == 0: #子进程范围print('这里是子进程,父进程pid:%s,子进程pid:%s,子进程休眠10秒' % (os.getppid(),Os.getpid ()) #让子进程先休眠10秒,然后退出time.sleep(10)else: print('这里是父进程,父进程休眠600秒,所以保证子进程先退出')time.sleep(600SIG_IGN,意思是 执行结果如下:$ python3 Test.py这里是父进程,父进程休眠600秒,所以保证子进程先退出。下面是子进程,父进程pid:1659,子进程pid:1660,子进程休眠10秒。`这里程序没有退出,由于父进程处于睡眠状态600秒,我们将使用ps命令输出如下:$ PS-aux | GRE python 31 2 3 4 5 6 7 8 9 10 11wp 1659 0.1 0 23992 6688 pts/2s 21:57 0:00 python 3 test . py可以看到子进程没有变成僵尸进程。 (完 )推荐阅读:Python简明教程-21、Python继承与多态Python简明教程-22、Python闭包与装饰器简明教程-23、Python异常解析简明教程-24、Python文件读写简明教程-25、Python目录操作


  • 全部评论(0)
资讯详情页最新发布上方横幅
最新发布的资讯信息
【技术支持|常见问题】1556原创ng8文章搜索页面不齐(2024-05-01 14:43)
【技术支持|常见问题】1502企业站群-多域名跳转-多模板切换(2024-04-09 12:19)
【技术支持|常见问题】1126完美滑屏版视频只能显示10个(2024-03-29 13:37)
【技术支持|常见问题】响应式自适应代码(2024-03-24 14:23)
【技术支持|常见问题】1126完美滑屏版百度未授权使用地图api怎么办(2024-03-15 07:21)
【技术支持|常见问题】如何集成阿里通信短信接口(2024-02-19 21:48)
【技术支持|常见问题】算命网微信支付宝产品名称年份在哪修改?风水姻缘合婚配对_公司起名占卜八字算命算财运查吉凶源码(2024-01-07 12:27)
【域名/主机/服务器|】帝国CMS安装(2023-08-20 11:31)
【技术支持|常见问题】通过HTTPs测试Mozilla DNS {免费源码}(2022-11-04 10:37)
【技术支持|常见问题】别告诉我你没看过邰方这两则有思想的创意广告! (2022-11-04 10:37)

联系我们
Q Q:375457086
Q Q:526665408
电话:0755-84666665
微信:15999668636
联系客服
企业客服1 企业客服2 联系客服
86-755-84666665
手机版
手机版
扫一扫进手机版
返回顶部