1. 程式人生 > >Python3 與 C# 併發程式設計之~程序先導篇

Python3 與 C# 併發程式設計之~程序先導篇

2.2.殭屍程序和孤兒程序

先看看定義:

孤兒程序 :一個父程序退出,而它的一個或多個子程序還在執行,那麼那些子程序將成為孤兒程序。孤兒程序將被init程序(程序號為1)所收養,並由init程序對它們完成狀態收集工作。

殭屍程序 :一個程序使用fork建立子程序,如果子程序退出,而父程序並沒有呼叫wait或waitpid獲取子程序的狀態資訊,那麼子程序的程序描述符仍然儲存在系統中。這種程序稱之為僵死程序。

通俗講就是:

孤兒程序:你爸在你之前死了,你成了孤兒,然後你被程序1收養,你死後的事宜你乾爹幫你解決

殭屍程序:你掛了,你爸忙著幹其他事情沒有幫你安葬,你變成了孤魂野鬼,你的怨念一直長存世間

舉個例子看看:

import os
import time

def main():
    pid = os.fork()
    if pid == 0:
        print("子程序:Pid=%d,PPID=%d" % (os.getpid(), os.getppid()))
        time.sleep(1)  # 睡1s
    elif pid > 0:
        print("父程序:Pid=%d,PPID=%d" % (os.getpid(), os.getppid()))

    print("pid=%d,over"
% os.getpid()) if __name__ == '__main__': main()

輸出: 孤兒

import os
import time

def main():
    pid = os.fork()
    if pid == 0:
        print("子程序:Pid=%d,PPID=%d" % (os.getpid(), os.getppid()))
    elif pid > 0:
        print("父程序:Pid=%d,PPID=%d" % (os.getpid(), os.getppid()))
while True: print("父親我忙著呢,沒時間管你個小屁孩") time.sleep(1) print("pid=%d,over" % os.getpid()) if __name__ == '__main__': main()

輸出+測試: 殭屍

其實殭屍程序的危害真的很大,這也就是為什麼有些人為了追求效率過度呼叫底層,不考慮自己實際情況最後發現還不如用自託管的效率高

殭屍程序是殺不死的,必須殺死父類才能徹底解決它們,下面說說怎麼讓父程序為子程序‘收屍’

2.3.父程序回收子程序(wait and waitpid)

講解之前先簡單分析一下上面的Linux指令(防止有人不太清楚)

kill -9 pid ==> 以前逆天說過,是無條件殺死程序,其實這種說法不準確,應該是發訊號給某個程序

-9指的就是訊號道里面的SIGKILL(訊號終止),你寫成kill -SIGKILL pid也一樣

-9只是系統給的一種簡化寫法(好像記得1~31訊號,各個Linux中都差不多,其他的有點不一樣)

[email protected]:~/桌面/work/PC/python/Thread/Linux kill -l
 1) SIGHUP   2) SIGINT   3) SIGQUIT  4) SIGILL   5) SIGTRAP
 6) SIGABRT  7) SIGBUS   8) SIGFPE   9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG  24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF 28) SIGWINCH    29) SIGIO   30) SIGPWR
31) SIGSYS  34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

一般搜尋程序中的某個程式一般都是用這個:ps -aux | grep xxx|其實就是管道,用於有血緣關係程序間通訊,等會講)

如果安裝了pstree就更方便了:pstree 13570 -ps (Ubuntu自帶,CentOS要裝下yum install psmisc

systemd(1)───systemd(1160)───gnome-terminal-(21604)───bash(8169)───python3(13570)───python3(13571)

擴充套件:我們平時Ctrl+C其實就是給 2)SIGINT發一個訊號

2.3.1.wait

步入正題:

Python的Wait和C系列的稍有不同,這邊重點說說Python:

help(os.wait)

Help on built-in function wait in module posix:

wait()
    Wait for completion of a child process.

    Returns a tuple of information about the child process:
        (pid, status)

os.wait()返回一個元組,第一個是程序id,第二個是狀態,正常退出是0,被九號訊號乾死就返回9

來個案例:

import os
import time

def main():
    pid = os.fork()
    if pid == 0:
        print("子程序:Pid=%d,PPID=%d" % (os.getpid(), os.getppid()))
    elif pid > 0:
        print("父程序:Pid=%d,PPID=%d" % (os.getpid(), os.getppid()))
        wpid, status = os.wait()
        print(wpid)
        print(status)

    print("pid=%d,over" % os.getpid())

if __name__ == '__main__':
    main()

輸出:

父程序:Pid=22322,PPID=10139
子程序:Pid=22323,PPID=22322
pid=22323,over
22323
0
pid=22322,over

演示一下被9號訊號乾死的情況:

import os
import time

def main():
    pid = os.fork()
    if pid == 0:
        print("子程序:Pid=%d,PPID=%d" % (os.getpid(), os.getppid()))
        while True:
            print("孩子老卵,就是不聽話")
            time.sleep(1)
    elif pid > 0:
        print("父程序:Pid=%d,PPID=%d" % (os.getpid(), os.getppid()))
        wpid, status = os.wait()  # 呼叫一次只能回收一次,想都回收,就來個while迴圈,-1則退出
        print(wpid)
        print(status)
        if status == 0:
            print("正常退出")
        elif status == 9:
            print("被訊號9乾死了")

    print("pid=%d,over" % os.getpid())

if __name__ == '__main__':
    main()

輸出: 回收子程序

擴充套件:(回收所有子程序,status返回-1代表沒有子程序了,Python裡面沒有子程序會觸發異常)

import os
import time

def main():
    i = 0
    while i < 3:
        pid = os.fork()
        # 防止產生孫子程序(可以自己思索下)
        if pid == 0:
            break
        i += 1

    if i == 0:
        print("i=%d,子程序:Pid=%d,PPID=%d" % (i, os.getpid(), os.getppid()))
        time.sleep(1)
    elif i == 1:
        print("i=%d,子程序:Pid=%d,PPID=%d" % (i, os.getpid(), os.getppid()))
        time.sleep(1)
    elif i == 2:
        print("i=%d,子程序:Pid=%d,PPID=%d" % (i, os.getpid(), os.getppid()))
        time.sleep(3)
        while True:
            print("(PID=%d)我又老卵了,怎麼滴~" % os.getpid())
            time.sleep(3)
    elif i==3: # 迴圈結束後,父程序才會退出,這時候i=3
        print("i=%d,父程序:Pid=%d,PPID=%d" % (i, os.getpid(), os.getppid()))
        while True:
            print("等待回收子程序")
            try:
                wpid, status = os.wait()
                print(wpid)
                print(status)
                if status == 0:
                    print("正常退出")
                elif status == 9:
                    print("被訊號9乾死了")
            except OSError as ex:
                print(ex)
                break

    print("pid=%d,over,ppid=%d" % (os.getpid(), os.getppid()))

if __name__ == '__main__':
    main()

演示:看最後一句輸出,父程序掃尾工作做完就over了 回收所有子程序

2.3.2.waitpid

上面說的wait方法是阻塞程序的一種方式,waitpid可以設定不阻塞程序

help(os.waitpid)

Help on built-in function waitpid in module posix:

waitpid(pid, options, /)
    Wait for completion of a given child process.

    Returns a tuple of information regarding the child process:
        (pid, status)

    The options argument is ignored on Windows.

等待程序id為pid的程序結束,返回一個tuple,包括程序的程序ID和退出資訊(和os.wait()一樣),引數options會影響該函式的行為。在預設情況下,options的值為0。

  1. 如果pid是一個正數,waitpid()請求獲取一個pid指定的程序的退出資訊
  2. 如果pid為0,則等待並獲取當前程序組中的任何子程序的值
  3. 如果pid為-1,則等待當前程序的任何子程序
  4. 如果pid小於-1,則獲取程序組id為pid的絕對值的任何一個程序
  5. 當系統呼叫返回-1時,丟擲一個OSError異常。

官方原話是這樣的:(英語好的可以看看我有沒有翻譯錯)

If pid is greater than 0, waitpid() requests status information for that specific process.
If pid is 0, the request is for the status of any child in the process group of the current process. 
If pid is -1, the request pertains to any child of the current process. 
If pid is less than -1, status is requested for any process in the process group -pid (the absolute value of pid).

options:(巨集)

os.WNOHANG - 如果沒有子程序退出,則不阻塞waitpid()呼叫
os.WCONTINUED - 如果子程序從stop狀態變為繼續執行,則返回程序自前一次報告以來的資訊。
os.WUNTRACED - 如果子程序被停止過而且其狀態資訊還沒有報告過,則報告子程序的資訊。

補充:

  1. 程序組:每一個程序都屬於一個“程序組”,當一個程序被建立的時候,它預設是其父程序所在組的成員(你們一家
  2. 會 話:幾個程序組又構成一個會話(你們小區

用法和wait差不多,就是多了一個不阻塞執行緒的方法:

import os
import time

def main():
    pid = os.fork()

    if pid == 0:
        print("[子程序]PID:%d,PPID:%d" % (os.getpid(), os.getppid()))
        time.sleep(2)

    elif pid > 0:
        print("[父程序]PID:%d,PPID:%d" % (os.getpid(), os.getppid()))
        while True:
            try:
                wpid, status = os.waitpid(-1, os.WNOHANG)
                if wpid > 0:
                    print("回收子程序wpid:%d,狀態status:%d" % (wpid, status))
            except OSError:
                print("沒有子程序了")
                break

            print("父程序忙著掙錢養家呢~")
            time.sleep(3)

    print("[over]PID:%d,PPID:%d" % (os.getpid(), os.getppid()))

if __name__ == '__main__':
    main()

輸出:

[父程序]PID:1371,PPID:29604
[子程序]PID:1372,PPID:1371
父程序忙著掙錢養家呢~
[over]PID:1372,PPID:1371
回收子程序wpid:1372,狀態status:0
父程序忙著掙錢養家呢~
沒有子程序了
[over]PID:1371,PPID:29604

2.3.3.wait3 and wait4

help(os.wait3)

Help on built-in function wait3 in module posix:

wait3(options)
    Wait for completion of a child process.

    Returns a tuple of information about the child process:
      (pid, status, rusage)
help(os.wait4)

Help on built-in function wait4 in module posix:

wait4(pid, options)
    Wait for completion of a specific child process.

    Returns a tuple of information about the child process:
      (pid, status, rusage)

這個是Python擴充套件的方法,用法和wait、waitpid差不多,我就不一個個的舉例子了,以wait3為例

import os
import time

def main():
    pid = os.fork()

    if pid == 0:
        print("[子程序]PID:%d,PPID:%d" % (os.getpid(), os.getppid()))
        time.sleep(2)

    elif pid > 0:
        print("[父程序]PID:%d,PPID:%d" % (os.getpid(), os.getppid()))
        while True:
            try:
                wpid, status, rusage = os.wait3(os.WNOHANG)
                if wpid > 0:
                    print("回收子程序wpid:%d,狀態status:%d\n詳細資訊:%s" % (wpid, status,
                                                                 rusage))
            except OSError:
                print("沒有子程序了")
                break

            print("父程序忙著掙錢養家呢~")
            time.sleep(3)

    print("[over]PID:%d,PPID:%d" % (os.getpid(), os.getppid()))

if __name__ == '__main__':
    main()

輸出

[父程序]PID:2638,PPID:29604
[子程序]PID:2639,PPID:2638
父程序忙著掙錢養家呢~
[over]PID:2639,PPID:2638
回收子程序wpid:2639,狀態status:0
詳細資訊:resource.struct_rusage(ru_utime=0.0052179999999999995, ru_stime=0.0052179999999999995, ru_maxrss=7032, ru_ixrss=0, ru_idrss=0, ru_isrss=0, ru_minflt=869, ru_majflt=0, ru_nswap=0, ru_inblock=0, ru_oublock=0, ru_msgsnd=0, ru_msgrcv=0, ru_nsignals=0, ru_nvcsw=2, ru_nivcsw=0)
父程序忙著掙錢養家呢~
沒有子程序了
[over]PID:2638,PPID:29604

擴充套件:execl and execlp

之前有說fork後,相當於copy了一份,.text裡面放的是程式碼段,如果想要呼叫另一個程式,可以使用execlxxx,他會把.text裡面的程式碼替換掉

help(os.execl)

Help on function execl in module os:

execl(file, *args)
    execl(file, *args)

    Execute the executable file with argument list args, replacing the
    current process.
help(os.execlp)

Help on function execlp in module os:

execlp(file, *args)
    execlp(file, *args)

    Execute the executable file (which is searched for along PATH)
    with argument list args, replacing the current process.

來看個例子,os.execl("絕對路徑","引數或者指令") or os.execlp("Path中包含的命令","引數或者指令")

提示:檢視命令路徑:eg:which ls

import os

def main():
    pid = os.fork()
    if pid == 0:
        # 第二個引數不能為None,,第一個路徑為絕對路徑 eg:os.execl("/bin/ls"," ")
        os.execl("/bin/ls", "ls", "-al")
        # os.execlp("ls", "ls", "-al")  # 執行Path環境變數可以搜尋到的命令
        print("exec函式族會替換程式碼,我是不會被執行的,除非上面的出問題了")

    print("-" * 10)  # 父程序執行一次,子程序不會執行

if __name__ == '__main__':
    main()

注意輸出資訊:os.execlp("ls", "ls", "-al")

----------
總用量 28
drwxrwxr-x 6 dnt dnt 4096 7月  26 05:23 .
drwxrwxr-x 9 dnt dnt 4096 7月  24 20:55 ..
drwxr-xr-x 2 dnt dnt 4096 7月  19 14:47 .ipynb_checkpoints
drwxrwxr-x 6 dnt dnt 4096 7月  26 06:27 Linux
-rw-rw-r-- 1 dnt dnt   93 7月  26 05:49 temp.py
drwxrwxr-x 2 dnt dnt 4096 7月  24 15:29 .vscode
drwxrwxr-x 2 dnt dnt 4096 7月  25 12:18 程序

相關推薦

Python3 C# 併發程式設計程序先導

2.2.殭屍程序和孤兒程序¶ 先看看定義: 孤兒程序 :一個父程序退出,而它的一個或多個子程序還在執行,那麼那些子程序將成為孤兒程序。孤兒程序將被init程序(程序號為1)所收養,並由init程序對它們完成狀態收集工作。 殭屍程序 :一個程序使用fork建立子程序,如果子程序退出,而父程序並沒有

Python3 C# 併發程式設計 程序

NetCore併發程式設計¶  Python的執行緒、並行、協程下次說 先簡單說下概念(其實之前也有說,所以簡說下): 併發:同時做多件事情 多執行緒:併發的一種形式 並行處理:多執行緒的一種(執行緒池產生的一種併發型別,eg:非同步程式設計) 響應式程式設計:一種程式設計模式,對事件

Python3 C# 併發程式設計 執行緒上

2.2.加強篇¶ 其實以前的Linux中是沒有執行緒這個概念的,Windows程式設計師經常使用執行緒,這一看~方便啊,然後可能是當時程式設計師偷懶了,就把程序模組改了改(這就是為什麼之前說Linux下的多程序程式設計其實沒有Win下那麼“重量級”),弄了個精簡版程序==>執行緒(核心是分不出程序

Python3 C# 網路程式設計 網路基礎

最新版本檢視:https://www.cnblogs.com/dotnetcrazy/p/9919202.html 入門篇 官方文件:https://docs.python.org/3/library/ipc.html(程序間通訊和網路) 例項程式碼:https://github.com/lotapp/

Python3 C# 面向物件封裝

關於__name__在模組呼叫的時候會詳細說,你可以先這樣理解:如果直接執行py檔案就執行,別人呼叫那麼你的main就不執行了 標準寫法: # 1.匯入的模組 # 2.class的定義 # 3.其他方法定義 def main(): pass if __name__ ==

Python3 C# 面向物件異常相關

老師問了小明一聲,有幾個輸出? 小明驕傲的說道:“兩個,我寫了兩個異常處理,當然都執行了” 同學們又笑了,小潘調侃的說了句:“一看就知道去年C#沒好好學,這不都一樣嘛,遇到異常下面程式碼還執行嗎?用腦子好好想想” 當我們認為某些程式碼可能會出錯時,就可以用try來執行這段程式碼,如果執行出錯,則後續

Python3 C# 面向物件繼承多型

Python的多繼承最好是當C#或者Java裡面的介面使用,這樣結構不會混亂( 特殊情況除外) 來個例子: class Animal(object): pass class Flyable(object): """飛的方法""" pass class Ru

Python學習【第20】:互斥鎖以及程序之間的三種通訊方式(IPC)以及生產者個消費者模型 python併發程式設計程序1-----------互斥鎖程序間的通訊

python併發程式設計之多程序1-----------互斥鎖與程序間的通訊 一、互斥鎖 程序之間資料隔離,但是共享一套檔案系統,因而可以通過檔案來實現程序直接的通訊,

Python學習【第21】:程序池以及回撥函式 python併發程式設計程序2-------------資料共享及程序池和回撥函式

python併發程式設計之多程序2-------------資料共享及程序池和回撥函式 一、資料共享 1.程序間的通訊應該儘量避免共享資料的方式 2.程序

併發程式設計程序

一、什麼是程序 一個正在執行的程式稱之為程序 是一種抽象概念 表示一個執行某件事情的過程,程序的概念 起源於作業系統 第一代計算機 程式是固定 無法修改 某種計算機只能幹某種活 第二代批處理系統 需要人工參與 將程式攢成一批 統一執行,序列執行 提高計算機的的利用率 但是除錯麻煩

c++併發程式設計thread::join()和thread::detach()

thread::join(): 阻塞當前執行緒,直至 *this 所標識的執行緒完成其執行。*this 所標識的執行緒的完成同步於從 join() 的成功返回。 該方法簡單暴力,主執行緒等待子程序期間什麼都不能做。thread::join()會清理子執行緒相關的記憶體空間,

多執行緒併發程式設計基礎知識(上)

前言 幾乎所有的程式設計師都知道,現代作業系統進行資源分配的最小單元是程序,而作業系統進行運算排程的最小單元是執行緒,其實,在Linux中執行緒也可以看作是一種輕量級的程序,那麼執行緒是包含於程序之中的,是程序中實際的運作單位;同一程序中的多個執行緒共用同一塊

python併發程式設計程序、多執行緒、非同步和協程

一、多執行緒   多執行緒就是允許一個程序記憶體在多個控制權,以便讓多個函式同時處於啟用狀態,從而讓多個函式的操作同時執行。即使是單CPU的計算機,也可以通過不停地在不同執行緒的指令間切換,從而造成多執行緒同時執行的效果。   多執行緒相當於一個併發(concunrr

python併發程式設計程序理論部分

一 什麼是程序     程序:正在進行的一個過程或者說一個任務。而負責執行任務則是cpu。     舉例(單核+多道,實現多個程序的併發執行):     egon在一個時間段內有很多工要做:python備課的任務,寫書的任務,交女朋友的任務,王者榮耀上分的任務,       但egon同一時刻只能做一

python併發程式設計程序

一 multiprocessing模組介紹     python中的多執行緒無法利用多核優勢,如果想要充分地使用多核CPU的資源(os.cpu_count()檢視),在python中大部分情況需要使用多程序。Python提供了multiprocessing。    multiprocessing模組用來開啟

C++ 併發程式設計互斥鎖和條件變數的效能比較

介紹 本文以最簡單生產者消費者模型,通過執行程式,觀察該程序的cpu使用率,來對比使用互斥鎖 和 互斥鎖+條件變數的效能比較。 本例子的生產者消費者模型,1個生產者,5個消費者。 生產者執行緒往佇列裡放入資料,5個消費者執行緒從佇列取資料,取資料前需要判斷一下佇列中是否有資料,這個佇列是全域性佇列,是執行緒間

C#併發程式設計初識並行程式設計

寫在前面 之前微信公眾號裡有一位叫sara的朋友建議我寫一下Parallel的相關內容,因為手中商城的重構工作量較大,一時之間無法抽出時間。近日,這套系統已有階段性成果,所以準備寫一下Parallel的相關內容,正好也延續之前的C#併發程式設計系列。 Parallel是並行程式設計的相關內容,而Paralle

41、併發程式設計程序實操

### 一 multiprocessing模組介紹 python中的多執行緒無法利用多核優勢,如果想要充分地使用多核CPU的資源(os.cpu_count()檢視),在Python中大部分情況需要使用多程序。Python提供了multiprocessing。 multiprocessing模組用來開啟子程序

Java併發程式設計CAS第三-CAS的缺點及解決辦法

Java併發程式設計之CAS第三篇-CAS的缺點 通過前兩篇的文章介紹,我們知道了CAS是什麼以及檢視原始碼瞭解CAS原理。那麼在多執行緒併發環境中,的缺點是什麼呢?這篇文章我們就來討論討論 本篇是《凱哥(凱哥Java:kagejava)併發程式設計學習》系列之《CAS系列》教程的第三篇:CAS的缺點有哪些?

Python3 C# 面向對象異常相關

efi bsp sof 一個 name final href 場景 插件 周末多碼文,昨天晚上一篇,今天再來一篇: 在線編程:https://mybinder.org/v2/gh/lotapp/BaseCode/master 在線預覽:http://github.les