Help us understand the problem. What is going on with this article?

go advent calendarの記事をいいね数でソートしてみた

More than 1 year has passed since last update.

こんにちわ、@smith_30です。
go4も最後となってしまったので最後にしかできない事をやってみました。

私のgoとの付き合いは今年からですがとても好きです。
書きやすい&読みやすいですし
特にgoroutineに慣れてくると色々なことを並行処理で
効率よく実行できると楽しいです。

そんなこともあってかgoを好きなエンジニアはとても多いらしく
goのアドベントカレンダーは4つもあります。

どの記事も素晴らしいとは思うのですが、いいねを多く集めてる注目されてる記事を
パパっと見たくはありませんか?

そこで、goroutineの練習がてらgoのアドベントカレンダーに投稿されている
記事をいいね順にソートして出力するスクリプトを書きました

こちら
qiita-adv-calendar

実行結果

$ ./build/bin/qiita-adv -n go -c 4 # goカレンダーの4つを対象にする

qiita_adv.mov.gif

全体構成

                     +-------------+
        +------------+ aggregateCh <--------------------------------------------------------------+
        |            +------+------+                                                              |
        |                   |                                    +-----------+                    |
        |                   |                             +->   +----------+ |  +--+              |
 +------v------+      +-----+------+   +------------+     |    +---------+ +-+     |       +------+------+
 | []*GridData +------+ Aggregater +---+ Dispatcher +-------> +--------+ +-+    +--------> | aggregateCh |
 +------+------+      +-----+------+   +-----+------+     |   | Fetcher+-+         |       +-------------+
        |                   |                |            +-> +---^----+        +--+                                      +-----------+
        |                   |             +--+----+               |                    +-------------+                    |           |
    +---+----+              |  +----------> queue |               +--------------------+  Req / Res  +--------------------> qiita api |
    |        |              |  |          +-------+                                    +-------------+                    |           |
    |  Sort  |       +------+--+----+                                                                                     +-----------+
    |        |       | gridUpdateCh <--------------------------------------------------------------------------+
    +---+----+       +--------------+                                                  +------+                |
        |                                              +----------+                +-> | Grid | +-----------+  |
        |                                    +------>  |          +----------------+   +------+             |  |
Finish  ^                                    |       +-+--------+ |                                         |  |
   +----+---+                                +---->  |          +---+  +------+   +-----------------------+ |  |
   |        |              Start             |     +-+--------+ | | +--> Grid +-+ +                       | |  |
   | Output |        +----------------+      |     |          | +-+    +------+ |                         | |  |
   |        |        | GridAggregater +------+---> | Calendar +-+       +-------+                        +v-v--+--------+
   +--------+        +----------------+            |          +----+               +-------------------> | gridUpdateCh |
                                                   +----------+    |  +------+     |                     +--------------+
                                                                   +> | Grid +-+ +-+
                                                                      +------+ |
                                                                       +-------+

やってること

  • AggregaterがgridUpdateCh(qiita apiに投げるためのGrid)を引いておく。
type Grid struct {
    URL      string
    QiitaURL string
    Title    string
    Like     int
}
  • GridAggregaterがカレンダー数分のgoroutineを動かす(Calendarが管理)
  • Calendarが受け取ったurlにあるGridを取得する(go-queryを使用)
  • Gridには外部のブログリンクもあるのでqiitaの記事のみGridとしてセットしgridUpdateChに投げる
  • AggregaterはgridUpdateChからGridを取り出してdispatcherのqueueに流し、dispatcherがfetcherに渡す
    (dispatcherをかませているのはgoroutineの数を制御するため)
  • fetcherはGridの持つURLをqiita apiに投げていいねの情報を埋め込みaggregateChに投げる
  • aggregateChからGridを引いてスライスに溜め込む。
  • すべてのgridの情報が更新されたらaggregateChを閉じる
  • スライスに入ったGrid情報をいいね順に並び替えて出力する

実装して学んだこと, tips

  • チャンネルを通してデータの連携を行う時はデータを受ける側が先にチャンネルを引くようにする

ex.)カレンダーにGrid情報を取得させてその情報を受取りたいとき

grid_aggregater.go
func (cs *GridAggregater) FetchGrids(gridUpdateCh chan *model.Grid) {
    for _, ca := range cs.C {
        cs.wg.Add(1)
        go func(c *model.Calendar) {
            cs.logger.Infof("calendar %s is start.", c.URL)
            // 裏でgoroutineを動かす
            // goroutineが書き込むチャンネルを受け取る
            gridCh := c.SetExecuteURLs() 

            for g := range gridCh {
         // channelから引いた値を別のチャンネルに送る
                gridUpdateCh <- g
            }
            cs.wg.Done()
        }(ca)
    }
}

c.SetExecuteURLs()実行部分

calendar.go
func (c *Calendar) SetExecuteURLs() <-chan *Grid {
    gridCh := make(chan *Grid, 25)

    go func() {
        defer close(gridCh)

        // 
        // カレンダー内のgrid情報を取得する -> g
        //

        gridCh <- g
    }()

    return gridCh
}

処理が終わったらcloseすることで、channelをforで引いている側の処理が終わる。
for でチャンネルを引いている部分はチャンネルが閉じられると
送信されたデータをすべて引いた後に処理を抜ける。
処理中の gridUpdateCh も事前にfor rangeでデータを引けるようにしています

  • apiでのレスポンスは json-to-go使うと便利

-> jsonはっつければgoのstructに変換してくれる。

  • dispatcher - workerの仕組みは参考にのっけたのでgo歴の浅い方は参考にされるとよいかと思います

僕も参考にしてほぼコピペで使わせてもらいました。

ほんとに簡潔に書くと

- dispatcherはworker(目的の処理を行うgoroutine)をpoolとして決まった数もっている。

- dispatcherはqueue(interface{})を持っていて、そのqueueにデータを流すと
  自身が持っているworkerを取得し、workerにデータを渡すことで処理を委譲しています。

- workerは親であるdispatcherを持っていて、そのdispatcherに自身が行った処理の終了通知をして
  親のdispatcherのpoolに戻るようになっている

単なる親子関係でないっていうのが面白い。。

さいごに

ちなみに今のところ一番上に来るのは mattn さんの記事でした!

171, 男と女が寄りそうとどうなるのか, https://qiita.com/mattn/items/14229755ac9427ecdd1f

57, Goでテストを書く(テストの実装パターン集), https://qiita.com/atotto/items/f6b8c773264a3183a53c

53, Go言語で「なかった」の返し方, https://qiita.com/najeira/items/0bb0acdd7a71fc3f559b
.
.
.

25日時点なので直近での記事は上位に来づらいことはお許しください<(_ _)>

参考

画面キャプチャ(gyazoではうまいこと収まり切らなかったので)
https://qiita.com/YosukeItabashi/items/5722395218e6e592fd39

dispatcherでのgoroutine制御
http://blog.kaneshin.co/entry/2016/08/18/190435

ascii generater(テキストからasciiに変換してくれるやつ)
http://patorjk.com/software/taag/#p=display&f=Graffiti&t=Type%20Something%20

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした