黄色网页视频 I 影音先锋日日狠狠久久 I 秋霞午夜毛片 I 秋霞一二三区 I 国产成人片无码视频 I 国产 精品 自在自线 I av免费观看网站 I 日本精品久久久久中文字幕5 I 91看视频 I 看全色黄大色黄女片18 I 精品不卡一区 I 亚洲最新精品 I 欧美 激情 在线 I 人妻少妇精品久久 I 国产99视频精品免费专区 I 欧美影院 I 欧美精品在欧美一区二区少妇 I av大片网站 I 国产精品黄色片 I 888久久 I 狠狠干最新 I 看看黄色一级片 I 黄色精品久久 I 三级av在线 I 69色综合 I 国产日韩欧美91 I 亚洲精品偷拍 I 激情小说亚洲图片 I 久久国产视频精品 I 国产综合精品一区二区三区 I 色婷婷国产 I 最新成人av在线 I 国产私拍精品 I 日韩成人影音 I 日日夜夜天天综合

python多進(jìn)程——fork()

系統(tǒng) 2034 0

  簡介                              ??

  程序每次執(zhí)行時,操作系統(tǒng)都會創(chuàng)建一個新進(jìn)程來運行程序指令。進(jìn)程中可調(diào)用os.fork,要求操作系統(tǒng)新建一個子進(jìn)程. [Windowsc系統(tǒng)中,os模塊沒有os.fork函數(shù)]。

  每個進(jìn)程都有一個不重復(fù)的進(jìn)程ID號?;蚍Qpid,它對進(jìn)程進(jìn)行標(biāo)識。子進(jìn)程與父進(jìn)程完全相同,子進(jìn)程從父進(jìn)程繼承了多個值的拷貝。如全局變量和環(huán)境變量。fork后,子進(jìn)程接收返回值0,而父進(jìn)程接收子進(jìn)程的pid作為返回值

os. fork ( )

Fork a child process. Return? 0 ?in the child and the child’s process id in the parent. If an error occurs OSError is?raised.

Note that some platforms including FreeBSD <= 6.3 and Cygwin have known issues when using fork() from a thread.

Availability: Unix ? >? 僅支持基于Unix核心的系統(tǒng)

python文檔

(一)fork函數(shù) 在子進(jìn)程中返回0,在父進(jìn)程中返回子進(jìn)程的id:      

  • os.getpid()   返回進(jìn)程pid

  • os.getppid()  返回父進(jìn)程pid

            
              #
            
            
               -*-coding:utf-8-*-
            
            
              import
            
            
               os

            
            
              import
            
            
               time

            
            
              print
            
            (
            
              '
            
            
              before calling
            
            
              '
            
            
              )

p 
            
            = os.fork()  
            
              #
            
            
               主進(jìn)程,子進(jìn)程同時向下執(zhí)行
            
            
              print
            
            (
            
              '
            
            
              after calling
            
            
              '
            
            
              )


            
            
              if
            
             p ==
            
               0:
    
            
            
              print
            
            (
            
              '
            
            
              執(zhí)行子進(jìn)程, pid={} ppid={} p={}
            
            
              '
            
            
              .format(os.getpid(), os.getppid(), p))

            
            
              else
            
            
              :
    
            
            
              print
            
            (
            
              '
            
            
              執(zhí)行主進(jìn)程, pid={} ppid={} p={}
            
            
              '
            
            .format(os.getpid(), os.getppid(), p))
          
            
              [root@192 ~]# python fork.py 
before calling
after calling
執(zhí)行主進(jìn)程, pid=1629 ppid=1572 p=1630
after calling
執(zhí)行子進(jìn)程, pid=1630 ppid=1629 p=0
            
          

結(jié)論:調(diào)用os.fork()之后,主進(jìn)程和子進(jìn)程同時執(zhí)行該行以下的代碼, 子進(jìn)程中fork函數(shù)返回0 父進(jìn)程中返回1630 ,即子進(jìn)程的pid.

再看下面的代碼結(jié)果:

            
              #
            
            
               -*-coding:utf-8-*-
            
            
              import
            
            
               os

            
            
              import
            
            
               time

            
            
              print
            
            (
            
              '
            
            
              before calling
            
            
              '
            
            
              )

p 
            
            = os.fork()  
            
              #
            
            
               主進(jìn)程,子進(jìn)程同時向下執(zhí)行
            
            
              print
            
            (
            
              '
            
            
              after calling
            
            
              '
            
            
              )


            
            
              if
            
             p ==
            
               0:
    
            
            
              print
            
            (
            
              '
            
            
              執(zhí)行子進(jìn)程, pid={} ppid={} p={}
            
            
              '
            
            
              .format(os.getpid(), os.getppid(), p))
    time.sleep(
            
            1
            
              )
    
            
            
              print
            
            (
            
              '
            
            
              執(zhí)行子進(jìn)程, pid={} ppid={} p={}
            
            
              '
            
            
              .format(os.getpid(), os.getppid(), p))

            
            
              else
            
            
              :
    
            
            
              print
            
            (
            
              '
            
            
              執(zhí)行主進(jìn)程, pid={} ppid={} p={}
            
            
              '
            
            .format(os.getpid(), os.getppid(), p))
          
            
              [root@192 ~]# python fork.py 
before calling
after calling
執(zhí)行主進(jìn)程, pid=1648 ppid=1572 p=1649
after calling
執(zhí)行子進(jìn)程, pid=1649 ppid=1648 p=0
[root@192 ~]# 執(zhí)行子進(jìn)程, pid=1649 ppid=1 p=0
            
          

子進(jìn)程先打印一段信息,再睡一秒,再打印一段信息,在子進(jìn)程輸出的兩次信息中,ppid分別是1648和1。 —— ?問1:ppid怎么變了?

接下來進(jìn)行探討:

二)fork()開啟進(jìn)程,主進(jìn)程執(zhí)行結(jié)束后,不會等待子進(jìn)程:       ?

實踐:后臺執(zhí)行下面的代碼,讓主進(jìn)程睡五秒,子進(jìn)程睡十秒:

            
              #
            
            
               -*-coding:utf-8-*-
            
            
              import
            
            
               os

            
            
              import
            
            
               time

p 
            
            =
            
               os.fork()


            
            
              if
            
             p ==
            
               0:
    time.sleep(
            
            10
            
              )
    
            
            
              print
            
            (
            
              '
            
            
              執(zhí)行子進(jìn)程, pid={} ppid={} p={}
            
            
              '
            
            
              .format(os.getpid(), os.getppid(), p))

            
            
              else
            
            
              :
    time.sleep(
            
            5
            
              )
    
            
            
              print
            
            (
            
              '
            
            
              執(zhí)行主進(jìn)程, pid={} ppid={} p={}
            
            
              '
            
            .format(os.getpid(), os.getppid(), p))
          
            
              [root@192 ~]# python fork.py &   ### 后臺執(zhí)行python代碼
[1] 1693

### 五秒前,查看進(jìn)程信息:主進(jìn)程為1693,子進(jìn)程為1694

[root@192 ~]# ps aux | grep fork.py
root       1693  0.0  0.1 125432  4592 pts/0    S    21:23   0:00 python fork.py
root       1694  0.0  0.0 125432  2748 pts/0    S    21:23   0:00 python fork.py
root       1696  0.0  0.0 112704   980 pts/0    S+   21:23   0:00 grep --color=auto fork.py
[root@192 ~]# 執(zhí)行主進(jìn)程, pid=1693 ppid=1572 p=1694  (此為程序打印信息,說明主進(jìn)程已執(zhí)行完)

[1]+  Done                    python fork.py

### 五秒后,主進(jìn)程執(zhí)行完畢,查看進(jìn)程信息:只剩子進(jìn)程1694

[root@192 ~]# ps aux | grep fork.py
root       1694  0.0  0.0 125432  2748 pts/0    S    21:23   0:00 python fork.py
root       1698  0.0  0.0 112704   980 pts/0    S+   21:23   0:00 grep --color=auto fork.py
[root@192 ~]# 執(zhí)行子進(jìn)程, pid=1694 ppid=1 p=0    (此為程序打印信息,說明子進(jìn)程已執(zhí)行完。 *注意,這里ppid是1)

### 十秒后,子進(jìn)程執(zhí)行完畢,子進(jìn)程結(jié)束

[root@192 ~]# ps aux | grep fork.py
root       1708  0.0  0.0 112704   980 pts/0    S+   21:23   0:00 grep --color=auto fork.py
            
          

現(xiàn)象:五秒前,兩個進(jìn)程都在執(zhí)行,五秒后,主進(jìn)程結(jié)束,只剩一個子進(jìn)程(說明父進(jìn)程沒有等待子進(jìn)程),十秒后,子進(jìn)程結(jié)束

結(jié)論:父進(jìn)程執(zhí)行結(jié)束后不等待子進(jìn)程

問1的解釋 :子進(jìn)程第一次打印時,剛好父進(jìn)程還未結(jié)束,還可以獲取到父進(jìn)程ppid,因此第一次打印的ppid是父進(jìn)程的pid,當(dāng)睡了一秒以后,父進(jìn)程早就執(zhí)行完了,溜了,沒有等待子進(jìn)程,因此子進(jìn)程交給了init進(jìn)程, ppid就變成1.

(三)僵尸進(jìn)程:                           ?

?

  若子進(jìn)程比父進(jìn)程先結(jié)束,而父進(jìn)程又沒有回收子進(jìn)程,釋放子進(jìn)程占用的資源,此時子進(jìn)程將成為一個僵尸進(jìn)程。

?

有什么壞處?  如果大量的產(chǎn)生僵尸進(jìn)程,將因為沒有可用的進(jìn)程號而導(dǎo)致系統(tǒng)不能產(chǎn)生新的進(jìn)程. 此即為僵尸進(jìn)程的危害,應(yīng)當(dāng)避免。

?僵尸進(jìn)程的避免:

  1. 父進(jìn)程通過 os. wait() os.waitpid() 等函數(shù)等待子進(jìn)程結(jié)束,這會導(dǎo)致父進(jìn)程掛起。
  2. 如果父進(jìn)程很忙,那么可以用signal函數(shù)為SIGCHLD安裝handler,因為子進(jìn)程結(jié)束后, 父進(jìn)程會收到該信號,可以在handler中調(diào)用wait回收。
  3. 如果父進(jìn)程不關(guān)心子進(jìn)程什么時候結(jié)束,那么可以用signal(SIGCHLD,SIG_IGN) 通知內(nèi)核,自己對子進(jìn)程的結(jié)束不感興趣,那么子進(jìn)程結(jié)束后,內(nèi)核會回收, 并不再給父進(jìn)程發(fā)送信號。
  4. 還有一些技巧,就是fork兩次,父進(jìn)程fork一個子進(jìn)程,然后繼續(xù)工作,子進(jìn)程fork一 個孫進(jìn)程后退出,那么孫進(jìn)程被init接管,孫進(jìn)程結(jié)束后,init會回收。不過子進(jìn)程的回收 還要自己做。

子進(jìn)程變成僵尸進(jìn)程,是因為父進(jìn)程先執(zhí)行完,沒有替子進(jìn)程收尸。而wait()并不是用來收尸的,只是防止父進(jìn)程先于子進(jìn)程退出;如果父進(jìn)程先退出,會使子進(jìn)程成為僵尸進(jìn)程,這時候子進(jìn)程的收尸就由1號init進(jìn)程來回收。

主進(jìn)程通過調(diào)用os.wait()等待子進(jìn)程結(jié) 束:

            
              #
            
            
               -*-coding:utf-8-*-
            
            
              import
            
            
               os

            
            
              import
            
            
               time

p 
            
            =
            
               os.fork()


            
            
              if
            
             p ==
            
               0:
    time.sleep(
            
            10
            
              )
    
            
            
              print
            
            (
            
              '
            
            
              執(zhí)行子進(jìn)程, pid={} ppid={} p={}
            
            
              '
            
            
              .format(os.getpid(), os.getppid(), p))

            
            
              else
            
            
              :
    time.sleep(
            
            5
            
              )
    
            
            
              print
            
            (
            
              '
            
            
              執(zhí)行主進(jìn)程, pid={} ppid={} p={}
            
            
              '
            
            
              .format(os.getpid(), os.getppid(), p))
    os.wait()
            
          
            
              [root@192 ~]# python fork.py &   # 后臺執(zhí)行python代碼

### 五秒前,查看進(jìn)程信息:主進(jìn)程為1751,子進(jìn)程為1752

[1] 1751
[root@192 ~]# ps aux | grep fork.py
root       1751  0.5  0.1 125432  4588 pts/0    S    21:29   0:00 python fork.py
root       1752  0.0  0.0 125432  2748 pts/0    S    21:29   0:00 python fork.py
root       1754  0.0  0.0 112704   980 pts/0    S+   21:29   0:00 grep --color=auto fork.py
[root@192 ~]# 執(zhí)行主進(jìn)程, pid=1751 ppid=1572 p=1752  (此為程序打印信息,說明主進(jìn)程已執(zhí)行到os.wait())

### 五秒后,主程序打印了信息并調(diào)用了os.wait(),查看進(jìn)程信息:主進(jìn)程為1751,子進(jìn)程為1752,主進(jìn)程沒有結(jié)束

[root@192 ~]# ps aux | grep fork.py
root       1751  0.1  0.1 125436  4588 pts/0    S    21:29   0:00 python fork.py
root       1752  0.0  0.0 125432  2748 pts/0    S    21:29   0:00 python fork.py
root       1756  0.0  0.0 112704   980 pts/0    S+   21:29   0:00 grep --color=auto fork.py
[root@192 ~]# 執(zhí)行子進(jìn)程, pid=1752 ppid=1751 p=0  (此為程序打印信息,說明子進(jìn)程已執(zhí)行完。 *注意,這里ppid不是1)

[1]+  Done                    python fork.py

### 十秒后,子進(jìn)程執(zhí)行完畢,子進(jìn)程結(jié)束,父進(jìn)程隨著子進(jìn)程的結(jié)束而結(jié)束

[root@192 ~]# ps aux | grep fork.py
root       1758  0.0  0.0 112704   980 pts/0    S+   21:29   0:00 grep --color=auto fork.py
            
          

現(xiàn)象:五秒前,兩個進(jìn)程都在執(zhí)行,五秒后,主進(jìn)程執(zhí)行完成并調(diào)用了os.wait(),等待子進(jìn)程結(jié)束,十秒后,子進(jìn)程結(jié)束,父進(jìn)程也隨之結(jié)束

結(jié)論:父進(jìn)程可調(diào)用os.wait()等待子進(jìn)程結(jié)束。 *沒有子進(jìn)程就調(diào)用os.wait()會拋異常: OSError: [Errno 10] No child processes

(四)進(jìn)程間資源獨立:                        ?

實踐:在fork()函數(shù)前定義一個變量,在子進(jìn)程中修改值,再從主進(jìn)程中查看變量是否被修改:

            
              #
            
            
               -*-coding:utf-8-*-
            
            
              import
            
            
               os

            
            
              import
            
            
               time

variable 
            
            =
            
               []
p 
            
            =
            
               os.fork()

            
            
              if
            
             p ==
            
               0:
    variable.append(
            
            1
            
              )
    
            
            
              print
            
            (
            
              '
            
            
              子進(jìn)程 variable_id={}
            
            
              '
            
            
              .format(id(variable)))
    
            
            
              print
            
            (
            
              '
            
            
              子進(jìn)程 variable={}
            
            
              '
            
            
              .format(variable))

            
            
              else
            
            
              :
    time.sleep(
            
            1)  
            
              #
            
            
               睡一秒,讓子進(jìn)程先改變變量的值
            
            
              print
            
            (
            
              '
            
            
              主進(jìn)程 variable_id={}
            
            
              '
            
            
              .format(id(variable)))
    
            
            
              print
            
            (
            
              '
            
            
              主進(jìn)程 variable={}
            
            
              '
            
            
              .format(variable))
    os.wait()
            
          
            
              [root@192 ~]# python fork.py 
子進(jìn)程 variable_id=140426199897224
子進(jìn)程 variable=[1]
主進(jìn)程 variable_id=140426199897224
主進(jìn)程 variable=[]
            
          

結(jié)論:子進(jìn)程中改變了變量的值,但在父進(jìn)程中并未改變,說明進(jìn)程間全局變量不共享

問2:但為什么變量id一樣?

問2的解釋:?? 寫時復(fù)制技術(shù):內(nèi)核只為新生成的子進(jìn)程創(chuàng)建虛擬空間結(jié)構(gòu),它們復(fù)制于父進(jìn)程的虛擬空間結(jié)構(gòu),但是不為這些段分配物理內(nèi)存,它們共享父進(jìn)程的物理空間,當(dāng)父子進(jìn)程中有更改相應(yīng)段的行為發(fā)生時,再為子進(jìn)程相應(yīng)的段分配物理空間。因此不論子進(jìn)程有沒有修改操作,虛擬地址和父進(jìn)程是一樣的,兩個進(jìn)程查看變量的id值是相同的。

?另外,即使是兩個互不相干的進(jìn)程,若它們的邏輯地址相同,實際地址也是不同的,并不會產(chǎn)生沖突。

參考鏈接:

百度百科僵尸進(jìn)程

python的os模塊fork、wait、system、exec、popen、exit函數(shù)講解

父進(jìn)程調(diào)用wait函數(shù)究竟對子進(jìn)程做了什么?

Linux進(jìn)程管理——fork()和寫時復(fù)制

?

如有意見或建議,一起交流;如有侵權(quán),請告知刪除。

?


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論