從一道面試題來學習前臺進程和後臺進程、孤兒進程和僵屍進程

来源:https://www.cnblogs.com/huageyiyangdewo/archive/2023/04/17/17325168.html
-Advertisement-
Play Games

Gin 環境:https://goproxy.cn,driect github.com/gin-gonic/gin 介紹 Gin 是一個用 Go (Golang) 編寫的 Web 框架。 它具有類似 martini 的 API,性能要好得多,多虧了 httprouter,速度提高了 40 倍。 如果 ...


1、面試題介紹

以前面試,面試官問了一個問題,大意是:

我們在終端中,通過執行 python main.py 命令,會啟動一臺前臺進程直到程式結束。現在我還是想通過執行 python main.py ,啟動一個後臺進程,讓後臺進程運行我們的業務邏輯。這個時候應該怎麼做呢?

回答上面這道題,需要先瞭解什麼是前臺進程和後臺進程,什麼是孤兒進程和僵屍進程?接下來,我們先一起看看前臺進程和後臺進程,以及孤兒進程和僵屍進程。最後再通過編寫代碼來完成面試題的需求。

2、前臺進程和後臺進程

2.1 什麼是前臺進程

在 Linux 中,前臺進程是指當前正在運行的進程,它與用戶交互並占用終端。當用戶在終端中輸入命令時,該命令所啟動的進程就是前臺進程。

前臺進程會占用終端,直到它執行完畢或者被中斷(例如按下 Ctrl+C)。在前臺進程運行期間,用戶可以通過鍵盤輸入命令或者發送信號來與進程交互。

2.2 什麼是後臺進程

Linux 後臺進程是指在終端中運行的進程,但是不會占用終端的輸入輸出,而是在後臺運行

在 Linux 中,可以通過在命令後面加上 & 符號來將進程放到後臺運行。例如,運行命令 command & 就可以將 command 進程放到後臺運行。

後臺進程可以在終端關閉後繼續運行,也可以同時運行多個後臺進程。可以使用 jobs 命令查看當前運行的後臺進程,使用 fg 命令將後臺進程切換到前臺運行,使用 bg 命令將前臺進程切換到後臺運行。

需要註意的是,後臺進程在另外的終端是查看不到任何信息的,如果需要查看進程的輸出信息,一般是將輸出重定向到文件中,然後使用 tail 命令實時查看輸出。

2.3 前臺進程、後臺進程如何切換

在 Linux 中,可以使用以下命令將前臺進程切換到後臺進程:

  1. 使用 Ctrl + Z 將當前正在運行的前臺進程掛起。
  2. 使用 bg 命令將掛起的進程切換到後臺運行。

使用 command & ,這樣的方式是一開始就將 command 進程放到後臺運行。

我們通過下麵這個例子,來感受下前臺進程和後臺進程是如何切換的。

1、編寫 test.py文件。

import os
import time


def main():
    a = 1
    while True:
        time.sleep(1)
        a += 1
        print("a---->", a)
        if a > 30:
            break


if __name__ == '__main__':
    main()

2、通過 python test.py執行程式。然後使用ctrl + Z 是程式暫停到後臺。註意,這個時候程式不會再往下執行了。

  • 如果想程式繼續往下執行,使用 bg 命令將其切換到後臺運行。

  • 還有一種方式是:在最開始執行命令的時候,加上 &。即python main.py &

python test.py
a----> 2
a----> 3
^Z
[1]  + 1761 suspended  python test.py
sample_test [master●] %

3、通過jobs命令查詢後臺進程。

sample_test [master●] % jobs          
[1]  + suspended  python test.py
sample_test [master●] %

4、使用fg命令將指定的後臺進程切換到前臺運行。(fg %N,這裡的N是 jobs返回的序號,並不是進程的PID)

    
sample_test [master●] % fg %1     
[1]  + 1761 continued  python test.py
a----> 4
a----> 5
a----> 6
a----> 7

3、孤兒進程和僵屍進程

通過上面的講解,我們知道了什麼是後臺進程和前臺進程。接下來,我們再講講什麼是孤兒進程和僵屍進程。

3.1 什麼是孤兒進程

孤兒進程是指父進程已經結束或者異常退出,而子進程還在運行的情況下,子進程就會變成孤兒進程。孤兒進程會被操作系統的init進程接管init進程會成為孤兒進程的新的父進程,並負責回收孤兒進程的資源,避免資源泄露和浪費。

因此一般來說,孤兒進程並不會有什麼危害。

我們來看一個關於孤兒進程的例子:

在main函數中,創建子進程,然後讓父進程睡眠1s,讓子進程先運行列印出其進程id(pid)以及父進程id(ppid);隨後子進程睡眠3s(此時會調度到父進程運行直至結束),目的是讓父進程先於子進程結束,讓子進程有個孤兒的狀態;最後子進程再列印出其進程id(pid)以及父進程id(ppid);觀察兩次列印 其父進程id(ppid)的區別。

import os
import time


def main():
    pid = os.fork()  # 創建子進程
    if pid < 0:
        # 創建失敗
        print("fork failed!")
        exit(1)
    elif pid == 0:  # 子進程
        print("I am the child process.")
        print("pid:%d, ppid:%d " % (os.getpid(), os.getppid()))
        # 子進程睡眠3s,保證父進程先退出,此後子進程成為孤兒進程
        time.sleep(3)
        # 註意查看孤兒進程的父進程變化
        print("after sleep, pid:%d, ppid:%d" % (os.getpid(), os.getppid()))
        assert os.getppid() == 1
        print("child process is exited.")
    else:
        print("I am father process.")
        # 為保證子進程先運行,讓父進程睡眠1s
        time.sleep(1)
        print("father process is exited.")




if __name__ == '__main__':
    main()

執行結果:

運行結果表明:當父進程結束後,子進程成為了孤兒進程。因為它的父進程id(ppid)變成了1,即init進程成為該子進程的父進程了。

3.2 什麼是僵屍進程

Linux 僵屍進程是指已經結束執行的進程,但是其父進程還沒有對其進行處理,導致該進程的進程描述符仍然存在於系統中,這種進程被稱為僵屍進程

僵屍進程不會占用系統資源,但是如果大量的僵屍進程存在,會占用系統的進程描述符資源,導致系統進程描述符資源耗盡,從而導致系統崩潰。

為了避免僵屍進程的出現,父進程需要及時對其進行處理,可以使用 wait() 或 waitpid() 等系統調用來等待子進程結束並回收其資源。另外,也可以使用信號處理機制,在父進程中註冊 SIGCHLD 信號處理函數來處理子進程結束的信號。

關於僵屍進程的例子

在main函數中,創建子進程,然後讓父進程睡眠30s,讓子進程先終止(註意和孤兒進程例子的區別);這裡子進程結束後父進程沒有調用wait/waitpid函數獲取其狀態,用ps查看進程狀態可以看出子進程為僵屍狀態。

import os
import time


def main():
    pid = os.fork()  # 創建子進程
    if pid < 0:
        # 創建失敗
        print("fork failed!")
        exit(1)
    elif pid == 0:  # 子進程
        print("I am the child process.I am exited.")
        exit(0)
    else:
        print("I am father process.")
        #  父進程睡眠30s等待子進程退出,且沒有調用wait/waitpid獲取其狀態
        #  子進程會成為僵屍進程
        time.sleep(30)
        print("father process is exited.")




if __name__ == '__main__':
    main()

開一個終端,在終端是運行test.py

在子進程結束,父進程睡眠(還沒退出)的時候,再開一個終端用PS查看進程狀態。

註意:

  1. 任何一個子進程(init除外)在exit()之後,其實它並沒有真正的被銷毀,而是留下一個稱為僵屍進程(Zombie)的數據結構,等待父進程處理。這是每個子進程在結束時都要經過的階段。
  2. 如果子進程在exit()之後,父進程沒有來得及處理,這時用ps命令就能看到子進程的狀態是“Z”。如果父進程能及時處理,可能用ps命令就來不及看到子進程的僵屍狀態,但這並不等於子進程不經過僵屍狀態。
  3. 如果父進程在子進程結束之前退出,則子進程將由init接管。init將會以父進程的身份對僵屍狀態的子進程進行處理。
  4. 如果父進程是一個迴圈,不會結束,那麼子進程就會一直保持僵屍狀態,這就是系統中有時候會有很多僵屍進程的原因。

那麼如何殺死僵屍進程呢,可以查詢 僵屍進程與孤兒進程 鏈接,來進行學習,這裡就不再講述。

3.3 總結

  • 孤兒進程:父進程已亡,子進程成為孤兒,被init進程收養,由init進程對它們完成狀態收集工作,因此一般沒有壞的影響。
  • 僵屍進程:子進程已亡,父進程沒給子進程收屍,子進程成為僵屍進程,占用系統資源。

4、面試題解決方式

現在再回過頭來看 面試題的要求:

在終端中執行 python main.py命令,啟動後臺進程來進行業務處理。

那麼我們可以利用孤兒進程的特性,完成上面的需求。

1、通過 os.fork()創建子進程。

2、創建完成後,讓父進程退出,子進程繼續運行。

簡單案例:

import os
import time


def main():
    pid = os.fork()  # 創建子進程
    a = 0
    if pid < 0:
        # 創建失敗
        print("fork failed!")
        exit(1)
    elif pid == 0:  # 子進程
        for i in range(10):
            time.sleep(1)
            a += i
        print("child process calculate result: %d" % a)
    else:
        print("I am father process.")
        exit(0)


if __name__ == '__main__':
    main()
sample_test [master●] % python test.py
I am father process.


10秒鐘過後
sample_test [master●] % child process calculate result: 45

參考資料:

僵屍進程與孤兒進程


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • # 請先使用命令 pip install sxtwl 安裝依賴庫後,再執行以下腳本 import sxtwl ymc = ["正", "二", "三", "四", "五", "六", "七", "八", "九", "十" ,"冬", "臘"] rmc = ["初一", "初二", "初三", &qu ...
  • 源代碼下載鏈接: 一、賓館客房管理系統開發初衷 隨著互聯網技術的迅速發展,電腦技術的普及以及信息化時代的推波助瀾,賓館客房需求的逐漸增大,這也是挑戰了賓館客房管理方面的技術,以前的人工管理方式已經不再適應現在的環境,取而代之的是先進的賓館客房管理系統,提高了賓館的工作效率,為想要入住賓館的人提供更 ...
  • 代碼如下: import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.MultiFormatWriter; import com.google.zxin ...
  • 併發工具類 通常我們所說的併發包也就是java.util.concurrent(JUC),集中了Java併發的各種工具類, 合理地使用它們能幫忙我們快速地完成功能 。 作者: 博學谷狂野架構師 GitHub:GitHub地址 (有我精心準備的130本電子書PDF) 只分享乾貨、不吹水,讓我們一起加油 ...
  • 好消息:與上題的Emergency是同樣的方法。壞消息:又錯了&&c++真的比c方便太多太多。 A family hierarchy is usually presented by a pedigree tree. Your job is to count those family members ...
  • 安裝Zookeeper和Kafka集群 本文介紹如何安裝Zookeeper和Kafka集群。為了方便,介紹的是在一臺伺服器上的安裝,實際應該安裝在多台伺服器上,但步驟是一樣的。 安裝Zookeeper集群 下載安裝包 從官網上下載安裝包: curl https://dlcdn.apache.org/ ...
  • 原文鏈接:https://www.zhoubotong.site/post/94.html 說下背景吧,大家在開發中可能在不同的目錄(package)下定義了相同的struct(屬性參數完全一樣如名字、個數和類型),在方法調用傳參數的時候,可能是用到了其中某一個struct的引用。 那麼這裡就牽扯到 ...
  • Java的反射機制允許程式員在執行期藉助於Reflection API取得任何類的內部信息,並能操作對象的屬性和方法,在各類框架中應用非常廣泛。這一期是關於反射內容的筆記,包含Class類、Field類、Method類、Constructor類及相關方法。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...