摘要:多進程通信之一命名管道。多進程通信之三信號量與共享內存。共享內存是最快是進程間通信方式,因為個進程之間并不需要數據復制,而是直接操控同一份數據。的一些書籍中甚至不建議新手輕易使用這種進程間通信的方式,因為這是一種極易產生死鎖的解決方案。
[原文地址:https://blog.ti-node.com/blog...]
往往開啟多進程的目的是為了一起干活加速效率,前面說了不同進程之間的內存空間都是相互隔離的,也就說進程A是無法讀或寫進程B中的任何數據內容的,反之亦然。但是,有些時候,多個進程之間必須要有相互通知的機制,用職場上的話來說就叫“及時溝通”。大家都在一起做同一件事情的不同部分,彼此之間“及時溝通”是很重要的。
于是進程間通信就誕生了,英文縮寫IPC,全稱InterProcess Communication。
常見的進程間通信方式有:管道(分無名和有名兩種)、消息隊列、信號量、共享內存和socket,最后一種方式今天不提,放到后面的php socket編程中去說,重點說前四種方式。
管道是*NIX上常見的一個東西,大家平時使用linux的時候也都在用,簡單理解就是|,比如ps -aux|grep php這就是管道,大概意思類似于ps進程和grep進程兩個進程之間用|完成了通信。管道是一種半雙工(現在也有系統已經支持全雙工的管道)的工作方式,也就是說數據只能沿著管道的一個方向進行傳遞,不可以在同一個管道上反向傳數據。管道分為兩種,一種叫做未命名的管道,另一種叫做命名管道,未命名管道只能在擁有公共祖先的兩個進程之間使用,簡單理解就是只能用于父進程和和其子進程之間的通信,但是命名管道則可以用于任何兩個毫無關連的進程之間的通信(一會兒將要演示的將是這種命名管道)。
需要特殊指出的是消息隊列、信號量和共享內存這三種IPC同屬于XSI IPC(XSI可以認為是POSIX標準的超集,簡單粗暴理解為C++之于C)。這三種IPC在*NIX中一般都有兩個“名字”來為其命名,一個叫做標志符,一個叫做鍵(key)。標志符是一個非負整數,每當一個IPC結構被創建然后又被銷毀后,標志符便會+1一直加到整數的最大整數數值,而后又從0開始重新計算。既然是為了多進程通信使用,那么多進程在使用XSI IPC的時候就需要使用一個名字來找到相應的IPC,然后才能對其進行讀寫(術語叫做多個進程在同一個IPC結構上匯聚),所以POSIX建議是無論何時創建一個IPC結構,都應指定一個鍵(key)與之關聯。一句話總結就是:標志符是XSI IPC的內部名稱,鍵(key)是XSI IPC的外部名稱。
使多個進程在XSI IPC上匯聚的方法大概有如下三種:
使用指定鍵IPC_PRIVATE來創建一個IPC結構,然后將返回的標志符保存到一個文件中,然后進程之間通過讀取這個文件中的標志符進行通信。使用公共的頭文件。這么做的缺點是多了IO操作。
將共同認同的鍵寫入到公共頭文件中。這么做的缺點這個鍵可能已經與一個IPCi結構關聯,這樣在使用這個鍵創建結構的時候就可能會出錯,然后必須刪除已有的IPC結構再重新創建。
認同一個文件路徑名和項目ID,然后使用ftok將這兩個參數轉換成一個鍵。這將是我們使用的方式。
XSI IPC結構有一個與之對應的權限結構,叫做ipc_perm,這個結構中定義了IPC結構的創建者、擁有者等。
多進程通信之一:命名管道。 在php中,創建一個管道的函數叫做posix_mkfifo(),管道創建完成后其實就是一個文件,然后就可以用任何與讀寫文件相關的函數對其進行操作了,代碼大概演示一下:
0 ) { // 在父進程中 // 打開命名管道,然后讀取文本 $file = fopen( $pipe_file, "r" ); // 注意此處fread會被阻塞 $content = fread( $file, 1024 ); echo $content.PHP_EOL; // 注意此處再次阻塞,等待回收子進程,避免僵尸進程 pcntl_wait( $status ); }
運行結果如下:
多進程通信之二:消息隊列。這個怕是很多人都聽過,不過印象往往停留在kafka、rabbitmq之類的用于服務器解耦網絡消息隊列軟件上。消息隊列是消息的鏈接表(一種常見的數據結構),但是這種消息隊列存儲于系統內核中(不是用戶態),一般我們外部程序使用一個key來對消息隊列進行讀寫操作。在PHP中,是通過msg_*系列函數完成消息隊列操作的。
0 ) { // 在父進程中 // 使用msg_receive()函數獲取消息 msg_receive( $queue, 0, $msgtype, 1024, $message ); echo $message.PHP_EOL; // 用完了記得清理刪除消息隊列 msg_remove_queue( $queue ); pcnlt_wait( $status ); } else if( 0 == $pid ) { // 在子進程中 // 向消息隊列中寫入消息 // 使用msg_send()向消息隊列中寫入消息,具體可以參考文檔內容 msg_send( $queue, 1, "helloword" ); exit; }
運行結果如下:
但是,值得大家繼續深入研究的是msg_send()和msg_receive()兩個函數,這兩個的每一個參數都是非常值得深入研究和嘗試的。篇幅問題,這里就不再詳細描述。
多進程通信之三:信號量與共享內存。共享內存是最快是進程間通信方式,因為n個進程之間并不需要數據復制,而是直接操控同一份數據。實際上信號量和共享內存是分不開的,要用也是搭配著用。*NIX的一些書籍中甚至不建議新手輕易使用這種進程間通信的方式,因為這是一種極易產生死鎖的解決方案。共享內存顧名思義,就是一坨內存中的區域,可以讓多個進程進行讀寫。這里最大的問題就在于數據同步的問題,比如一個在更改數據的時候,另一個進程不可以讀,不然就會產生問題。所以為了解決這個問題才引入了信號量,信號量是一個計數器,是配合共享內存使用的,一般情況下流程如下:
當前進程獲取將使用的共享內存的信號量
如果信號量大于0,那么就表示這塊兒共享資源可以使用,然后進程將信號量減1
如果信號量為0,則進程進入休眠狀態一直到信號量大于0,進程喚醒開始從1
一個進程不再使用當前共享資源情況下,就會將信號量減1。這個地方,信號量的檢測并且減1是原子性的,也就說兩個操作必須一起成功,這是由系統內核來實現的。
在php中,信號量和共享內存先后一共也就這幾個函數:
其中,sem_是信號量相關函數,shm_是共享內存相關函數。
0 ) { $child_pid[] = $pid; } } while( !empty( $child_pid ) ){ foreach( $child_pid as $pid_key => $pid_item ){ pcntl_waitpid( $pid_item, $status, WNOHANG ); unset( $child_pid[ $pid_key ] ); } } // 休眠2秒鐘,2個子進程都執行完畢了 sleep( 2 ); echo "最終結果".shm_get_var( $shm_id, SHM_VAR ).PHP_EOL; // 記得刪除共享內存數據,刪除共享內存是有順序的,先remove后detach,順序反過來php可能會報錯 shm_remove( $shm_id ); shm_detach( $shm_id );
運行結果如下:
確切說,如果不用sem的話,上述的運行結果在一定概率下就會產生1而不是2。但是只要加入sem,那就一定保證100%是2,絕對不會出現其他數值。
[原文地址:https://blog.ti-node.com/blog...]
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/29368.html
摘要:因為子進程一定不會是組長進程,所以子進程可以調用。主進程退出子進程繼續執行啦啦啦,啦啦啦,啦啦啦,已經變成啦,開心一般服務器軟件都有寫配置項,比如以模式運行還是以模式運行。 [原文地址:https://blog.ti-node.com/blog...] 其實前面是談過一次daemon進程的,但是并涉及過多原理,但是并不影響使用。今天打算說說關于daemon進程更多的二三事,本質上說,如...
摘要:原文地址正如標題所言,顫顫抖抖開篇。于是只能是你自己,把單子上的個快遞逐次和收到的對比一遍,然后對比完畢后再把這個單子給了阿梅,然后阿梅繼續等。剃光頭前的阿梅,就是,不敢正眼看老板娘一眼。剃光頭后的阿梅,就是,可徒手接魔鬼隊的死亡之球。 [原文地址:https://blog.ti-node.com/blog...] 正如標題所言,顫顫抖抖開篇epoll。顫顫抖抖的原因大概也就是以前幾乎...
摘要:傳統的網頁編程采用的三劍客來實現,在微信小程序中同樣有三劍客。觀察者模式不難實現,重點是如何在微信小程序中搭配其特有的生命周期來使用。交互事件傳統的事件傳遞類型有冒泡型與捕獲型,微信小程序中自然也有。 本文由作者鄒永勝授權網易云社區發布。 簡介為了更好的展示我們即時通訊SDK強悍的能力,網易云信IM SDK微信小程序DEMO的開發就提上了日程。用產品的話說就是: 云信 IM 小程序 S...
閱讀 2291·2021-11-24 10:18
閱讀 2721·2021-11-19 09:59
閱讀 1712·2019-08-30 15:53
閱讀 1188·2019-08-30 15:53
閱讀 1071·2019-08-30 14:19
閱讀 2482·2019-08-30 13:14
閱讀 3005·2019-08-30 13:00
閱讀 1938·2019-08-30 11:11