去年我寫了《muduo 網路程式設計示例》系列文章,這些文章已經收入《linux 多執行緒服務端程式設計:使用 muduo c++ 網路庫》一書。這些文章講的基本都是執行在單機上的網路程式,每個例子都只有乙個程式(第7.13節例外)。我接下來打算繼續寫幾篇文章,談一談分布在多台機器上、協作發揮作用的網路程式設計例子。
今天先講第乙個,單詞計數及排序。單詞計數(word count),顧名思義就是統計乙個文字檔案裡邊每個詞出現了多少次。排序指的是按出現次數從多到少排序,也可以把問題改為「找出出現次數最多的1000個單詞」。
這個問題有三個層次,第一是輸入檔案比較小,能完全放入記憶體;第二是輸入檔案比較大,不能一次性都放入記憶體;第三是輸入檔案分布在多台機器上,這需要用到網路程式設計。
第乙個層次很好解決,幾十行**就搞定了。
第二個層次不難解決,基本思路是分而治之,先hash分塊統計單詞出現次數,將每一塊按出現次數排序,最後歸併。**見分析見
第三個層次也不難,可以當做網路程式設計的練習來做。如果有合適的框架,可以輕鬆解決,因為單詞計數是map reduce的經典範例,對出現次數排序也可以再用一步map reduce搞定(估計需要乙個好的 shuffle 函式,簡單hash是不行的)。
如果用普通網路程式設計,一種設計思路如下圖,其中方框代表機器,橢圓代表輸入輸出檔案,圓角矩形代表程序。思路跟第二個層次一樣,先hash到多個shard檔案(由hasher和receiver負責),再對每個shard檔案排序(由sender負責),最後歸併(merger)。
注意這種思路適合求top k元素,不適合按出現次數排序全部單詞,因為最終結果收集在一台機器上。目前這個sender實現的乙個限制是,每個shard必須能全部放入記憶體,因為sender對shard排序是在記憶體中進行的。如果資料更大,還需要實現單機外部排序。
圖中hasher和receiver的**見muduo示例中的muduo/examples/wordcount;sender和merger的**見注意merger沒有使用muduo,而是採用阻塞網路程式設計。有興趣的讀者可以思考其背後的原因。要想發揮 merger 正常的效能,需要修改 /usr/include/boost/asio/basic_socket_streambuf.hpp ,增大緩衝區,即 enum ;
這可以看作是map reduce的原始實現,或者說用map reduce的思想手寫了一些原始工具。如果把map reduce比作c語言,這裡的幾個程式相當於彙編寫的函式。
以後我再寫乙個按出現次數全排序的例子吧,需要替換這裡的sender和merger。
(.完.)
多協程爬蟲
要實現非同步的爬蟲方式的話,需要用到多協程。同步的爬蟲方式爬取這8個 import requests,time 匯入requests和time start time.time 記錄程式開始時間 url list 把8個 封裝成列表 for url in url list 遍歷url list r r...
gevent多協程運用
導包import gevent 猴子補丁 from gevent import monkey monkey.patch all from d8 db import connectmysql import time import pymysql 協程入庫 class myinsertgevent ob...
golang channel 多協程問題示例
package main import fmt time 使用channel一樣要遵守一些約定。乙個約定就是將記憶體的所有權交出去後,無論是通過記憶體指標,還是訊息控制,就不能再操作這塊記憶體。否則一樣會引入多執行緒問題 func main go func output arr time.sleep...