[Golang]實習最後一天小記念+併發爬蟲小練習

  今天是我在公司實習的最後一天,一個月的時間真的是過短暫了,我很是享受在公司工做的這一個月,在這裏Leader和同事們對個人幫助極大地促進了我技術水平的進步和自信心的提高,我發自心裏地感謝白山雲科技給我這樣一個實習的機會,謝謝大家對個人無私幫助(雖然他們可能也看不到…)。html

  眼看着暑假還剩不到一個月,其實我心裏是不想離開這個公司的,可是想到開學之後又要有各類網絡賽和區域賽,又有新生的到來,爲了校隊,我仍是離開吧(雖然我回去也沒啥卵用…)。git

  實習期間第一次寫函數式的程序,而且第一次完成了一個用於日誌分析的分佈式程序。還有騰訊的實時監控數據上報的需求的邊緣服務器日誌收集和彙總的功能,第一次爲本身的代碼寫了測試。第一次與他人真正地合做完成一個項目,雖然到今天下午的時候leader說騰訊給出了新接口,咱們分析了一下需求表示要改一大部分東西,不過我是沒有機會再作下去了,留給zzb同窗吧,估計他看了個人代碼要推翻重寫了,哈哈。github

  記得剛來的時候我一直擔憂leader分配給我任務,我作很差。可是心一橫接下來,無論作得好很差,只要用心去作,哪怕結果不盡人意,仍是會獲得寬容和承認(好吧我如今以爲我寫的東西都是一坨shi…)。golang

  人總歸有第一次,在隨後的磕磕絆絆中學習,直到作出一點微小的貢獻。慢慢地,力所能及的地方愈來愈高,直到本身羽翼豐滿,獨當一面,這就是奮鬥和成長最吸引人的地方了吧。算法

  不知不覺我就要大三了,大學生活已經度過了一半。大一大二的時候總以爲一些具體的技術我不必深究,因而就所有擱淺。通過此次實習個人心態有了變化,對本身將來的規劃也應當再作一些調整了:數據庫

多讀一些書,在內存管理、並行代碼編寫上多下一些功夫。算法再優雅但終歸是跑在單核上的,並行程序才適合這個時代。ubuntu

複習一下網絡和數據庫的內容。windows

多看一些語言的第三方庫,本身造輪子會浪費不少時間。服務器

多嘗試寫本身沒有寫過的東西,不要擔憂本身第一次寫不出來,誰都有第一次,第一次也每每不是順利的。網絡

複習好數學,繼續學習機器學習的知識。

刷題是必須持續進行的,幫助我提升思惟水平,以便更好地接受其餘知識。

系統地學一下Linux,而且和windows說再見。

  如今就想起來這麼多,等到之後繼續補充吧。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

  爬蟲的需求很簡單,就是從paste.ubuntu.com上搞別人貼的代碼,而後判斷是否是C/C++代碼。面臨着幾個問題須要考慮:

1、paste訪問的時間很長,這很影響爬蟲和內容處理的效率,這該怎麼辦:

  這個問題我使用了三種方法來解決,第一個是採用並行程序,這個就很少說了,多開幾個線程作處理會快些。第二個是預判這個文件的大小,設定一個閾值,保證這個文件超過閾值後必定不是C/C++的題解代碼,固然塞一張表除外,不過OJ通常限制65535B,咱們能夠取一半即30000B。第三個是設置timeout,在golang裏就須要手工創建一個client發送get請求了,這裏的具體函數以下:

func GetHtml(Url string, MagicNum string) []byte {
	timeout := time.Duration(15 * time.Second)
	client := http.Client{
		Timeout: timeout,
	}
	request, err := http.NewRequest(http.MethodGet, Url, nil)
	
	if err != nil {
		log.Errorln(err.Error())
		return nil
	}
	res, err := client.Do(request)
	if err != nil {
		log.Errorln(err.Error())
		return nil
	}
	result, err := ioutil.ReadAll(res.Body)
	if len(result) > 30000 {
		return nil
	}
	res.Body.Close()
	if err != nil {
		log.Errorln(err.Error())
		return nil
	}
	rd := bytes.NewReader(result)
	nd, err := goquery.Parse(rd)
	if err != nil {
		log.Panicln(err.Error())
	}
	str := nd.Find("td.code").Text()

	buf := []byte(str)
	return buf
}
GetHtml

2、判斷這個html中包含的代碼是C/C++代碼:

  這個我處理得很糙,就是去看看有沒有一個#include子串,固然這個子串是能夠增長的,不過可能影響效率。但願有更好辦法的朋友能夠留下你的方法,在此謝謝。

func Judge(buf []byte) bool {
	var patterns = []string{
		"#include",
	}
	n := len(patterns)
	for i := 0; i < n; i++ {
		ok, err := regexp.Match(patterns[i], buf)
		if ok {
			return true
		}
		if err != nil {
			log.Errorln(err.Error())
			return false
		}
	}
	return false
}
Judge

三、並行訪問時如何保證訪問不衝突:

  這個也很好解決,學過操做系統的人都明白能夠添加一個mutex來保證一個資源不被同時訪問。我這裏更新的是一個offset,道理是同樣的。這個os.Args[1]和offset都是全局變量,可是隻有offset須要寫,因此只給它加mutex就好了。

func numGetter(MagicNum string, ch chan int64) {
	Num, err := strconv.ParseInt(MagicNum, 10, 64)
	if err != nil {
		log.Errorln(err.Error())
		return
	}
	ch <- (Num + Offset)
	Offset++
}
numGetter
func NumGetter(Num string, ch chan int64) {
	for {
		mutex.Lock()
		numGetter(Num, ch)
		mutex.Unlock()
		Do(strconv.FormatInt(<-ch, 10))
	}
}
NumGetter

 

  最後並行程序,一個go就能夠解決~os.Args[2]用於設定線程數。

func main() {
	Offset = 0
	ch := make(chan int64, 10)
	n, err := strconv.ParseInt(os.Args[2], 10, 64)
	if err != nil {
		log.Errorln(err.Error())
		return
	}
	var i int64
	for i = 0; i < n; i++ {
		go NumGetter(os.Args[1], ch)
	}
	time.Sleep(time.Hour)
}
main

 

 

  這是我第一次嘗試用golang寫並行的爬蟲程序。我從學習寫golang到如今有半個月的時間了,是時候找一本書認真學習一下go這個美妙的語言了。如今寫的程序都是在翻譯本身腦子裏用其餘語言寫好的程序而已,我應該更多地去使用go語言的特性才能夠。

  ps: 使用了兩個go的第三方庫:

"github.com/Sirupsen/logrus"
"github.com/opesun/goquery"

附圖:

相關文章
相關標籤/搜索