{"action":"created","comment":{"url":"https://api.github.com/repos/studygolang/GCTT/pulls/comments/154896164","pull_request_review_id":81111398,"id":154896164,"diff_hunk":"@@ -0,0 +1,584 @@\n+# Go语言并发可视化\n+\n+本文作者提供了在 2016 的 GopherCon 上的关于 Go 并发可视化的[主题演讲视频](https://www.youtube.com/watch?v=KyuFeiG3Y60)。\n+\n+Go语言一个鲜明的优点就是内置的基于 [CSP](https://en.wikipedia.org/wiki/Communicating_sequential_processes) 的并发实现。Go 可以说是一个为了并发而设计的语言，允许我们使用它构建复杂的并发流水线。但是开发者是否在脑海中想象过不同的并发模式呢，它们在你的大脑中是怎样的形状？\n+\n+你肯定想过这些！我们都会靠多种多样的想象来思考。如果我让你想象一下 1-100 的数字，你会下意识地在脑海中闪过这些数字的图像。比如说我会把它想象成一条从我出发的直线，到 20 时它会右转 90 度并且一直延伸到 1000。这是因为我上幼儿园的时候，卫生间墙上写满了数字，20 正好在角落上。你们脑中肯定有自己想象的数字形象。另一个常见的例子就是一年四季的可视化，有些人把它想象成一个盒子，另外一些人把它想象成是圆圈。\n+\n+无论如何，我想要用 Go 和 WebGL 分享我想象的一些常用并发模式的可视化。这些可视化或多或少地代表了我头脑中的并发编程方法。如果能知道我们之间对并发可视化想象的差异，肯定是一件很有趣的事情。我尤其想要知道 Rob Pike 和 Sameer Ajmani 是怎么想象并发的，那一定很有意思。\n+\n+现在，我们就从最简单的 “Hello, Concurrent World” 开始，来了解我脑海中的并行世界吧。\n+\n+## Hello, Concurrent World\n+\n+这个例子的代码很简单，只包含一个 channel，一个 goroutine，一个读操作和一个写操作。\n+```go\n+package main\n+\n+func main() {\n+    // create new channel of type int\n+    ch := make(chan int)\n+\n+    // start new anonymous goroutine\n+    go func() {\n+        // send 42 to channel\n+        ch <- 42\n+    }()\n+    // read from channel\n+    <-ch\n+}\n+```\n+[WebGL 动画界面](http://divan.github.io/demos/hello)\n+\n+![hello](http://divan.github.io/demos/gifs/hello.gif)\n+\n+在这张图中，蓝色的线代表 goroutine 的时间轴。连接 `main` 和 `go#19` 的蓝线是用来标记 goroutine 的起始和终止并且表示父子关系的。红色的箭头代表的是 send/recv 操作。尽管 send/recv 操作是两个独立的操作，但是我试着将它们表示成一个操作 `从A发送到B`。右边蓝线上的 `#19` 是该 goroutine 的内部 ID，可以通过 Scott Mansfield 在 [Goroutine IDs](http://blog.sgmansfield.com/2015/12/goroutine-ids/)一文中提到的技巧获取。\n+\n+## 计时器（Timers）\n+事实上，我们可以通过简单的几个步骤编写一个计时器：创建一个 channel，启动一个 goroutine 以给定间隔往 channel 中写数据，将这个 chennel 返回给调用者。调用者阻塞地从 channel 中读，就会得到一个精准的时钟。让我们来试试调用这个程序 24 次并且将过程可视化。\n+```go\n+package main\n+\n+import \"time\"\n+\n+func timer(d time.Duration) <-chan int {\n+    c := make(chan int)\n+    go func() {\n+        time.Sleep(d)\n+        c <- 1\n+    }()\n+    return c\n+}\n+\n+func main() {\n+    for i := 0; i < 24; i++ {\n+        c := timer(1 * time.Second)\n+        <-c\n+    }\n+}\n+```\n+[WebGL 动画界面](http://divan.github.io/demos/timers/)\n+\n+![timers](http://divan.github.io/demos/gifs/timers.gif)\n+\n+这个效果是不是很有条理？\n+\n+## 乒乓球（Ping-pong）\n+这个例子是我从 Google 员工 Sameer Ajmani 的一次演讲[\"Advanced Go Concurrency Patterns\"](https://talks.golang.org/2013/advconc.slide#1)中找到的。当然，这并不是一个很高阶的并发模型，但是对于Go语言并发的新手来说是很有趣的。\n+\n+在这个例子中，我们定义了一个 channel 来作为“乒乓桌”。乒乓球是一个整形变量，代码中有两个 goroutine “玩家”通过增加乒乓球的 counter 在“打球”。\n+```go\n+package main\n+\n+import \"time\"\n+\n+func main() {\n+    var Ball int\n+    table := make(chan int)\n+    go player(table)\n+    go player(table)\n+\n+    table <- Ball\n+    time.Sleep(1 * time.Second)\n+    <-table\n+}\n+\n+func player(table chan int) {\n+    for {\n+        ball := <-table\n+        ball++\n+        time.Sleep(100 * time.Millisecond)\n+        table <- ball\n+    }\n+}\n+```\n+[WebGL 动画界面](http://divan.github.io/demos/pingpong/)\n+\n+![Ping-pong](http://divan.github.io/demos/gifs/pingpong.gif)\n+\n+我建议你点击 “WebGL 动画界面” 链接，从不同角度看看这个模型，并且试试它减速，加速的效果。\n+\n+现在，我们给这个模型添加一个玩家（goroutine）。\n+```go\n+ go player(table)\n+ go player(table)\n+ go player(table)\n+```\n+[WebGL 动画界面](http://divan.github.io/demos/pingpong3/)\n+\n+![Ping-pong2](http://divan.github.io/demos/gifs/pingpong3.gif)\n+\n+我们可以看到每个 goroutine 都有序地“打到球”，你可能会好奇这个行为的原因。那么，为什么这三个 goroutine 始终按照一定顺序接收到ball呢？\n+\n+答案很简单，Go运行时会对每个 channel 的所有接收者维护一个 FIFO 队列。在我们的例子中，每个 goroutine 会在它将 ball 传给 channel 之后就开始等待 channel，所以它们在队列里的顺序总是一定的。让我们增加 goroutine 的数量，看看顺序是否仍然保持一致。\n+```go\n+for i := 0; i < 100; i++ {\n+    go player(table)\n+}\n+```\n+[WebGL 动画界面](http://divan.github.io/demos/pingpong100/)\n+\n+![Ping-pong100](http://divan.github.io/demos/gifs/pingpong100.gif)\n+\n+很明显，它们的顺序仍然是一定的。我们可以创建一百万个 goroutine 去尝试，但是上面的实验已经足够让我们得出结论了。接下来，让我们来看看一些不一样的东西，比如说通用的消息模型。\n+\n+## 扇入（Fan-In）","path":"translated/tech/Visualizing Concurrency in Go.md","position":126,"original_position":126,"commit_id":"571d3700fc8da3127cad30e73b98c5d7c9560d60","original_commit_id":"571d3700fc8da3127cad30e73b98c5d7c9560d60","user":{"login":"rxcai","id":5463519,"avatar_url":"https://avatars1.githubusercontent.com/u/5463519?v=4","gravatar_id":"","url":"https://api.github.com/users/rxcai","html_url":"https://github.com/rxcai","followers_url":"https://api.github.com/users/rxcai/followers","following_url":"https://api.github.com/users/rxcai/following{/other_user}","gists_url":"https://api.github.com/users/rxcai/gists{/gist_id}","starred_url":"https://api.github.com/users/rxcai/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rxcai/subscriptions","organizations_url":"https://api.github.com/users/rxcai/orgs","repos_url":"https://api.github.com/users/rxcai/repos","events_url":"https://api.github.com/users/rxcai/events{/privacy}","received_events_url":"https://api.github.com/users/rxcai/received_events","type":"User","site_admin":false},"body":"建议小节名翻为：\r\n扇入模式（Fan-In）\r\n下文类似：\r\n工作者模式（Workers）\r\n等\r\n这样更加便于理解\r\n","created_at":"2017-12-05T10:00:30Z","updated_at":"2017-12-05T10:43:33Z","html_url":"https://github.com/studygolang/GCTT/pull/85#discussion_r154896164","pull_request_url":"https://api.github.com/repos/studygolang/GCTT/pulls/85","author_association":"COLLABORATOR","_links":{"self":{"href":"https://api.github.com/repos/studygolang/GCTT/pulls/comments/154896164"},"html":{"href":"https://github.com/studygolang/GCTT/pull/85#discussion_r154896164"},"pull_request":{"href":"https://api.github.com/repos/studygolang/GCTT/pulls/85"}}},"pull_request":{"url":"https://api.github.com/repos/studygolang/GCTT/pulls/85","id":155664145,"html_url":"https://github.com/studygolang/GCTT/pull/85","diff_url":"https://github.com/studygolang/GCTT/pull/85.diff","patch_url":"https://github.com/studygolang/GCTT/pull/85.patch","issue_url":"https://api.github.com/repos/studygolang/GCTT/issues/85","number":85,"state":"open","locked":false,"title":"完成翻译：Visualizing Concurrency in Go","user":{"login":"QueShengyao","id":10654767,"avatar_url":"https://avatars2.githubusercontent.com/u/10654767?v=4","gravatar_id":"","url":"https://api.github.com/users/QueShengyao","html_url":"https://github.com/QueShengyao","followers_url":"https://api.github.com/users/QueShengyao/followers","following_url":"https://api.github.com/users/QueShengyao/following{/other_user}","gists_url":"https://api.github.com/users/QueShengyao/gists{/gist_id}","starred_url":"https://api.github.com/users/QueShengyao/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/QueShengyao/subscriptions","organizations_url":"https://api.github.com/users/QueShengyao/orgs","repos_url":"https://api.github.com/users/QueShengyao/repos","events_url":"https://api.github.com/users/QueShengyao/events{/privacy}","received_events_url":"https://api.github.com/users/QueShengyao/received_events","type":"User","site_admin":false},"body":"","created_at":"2017-11-30T16:57:24Z","updated_at":"2017-12-05T10:43:33Z","closed_at":null,"merged_at":null,"merge_commit_sha":"dc815e44f9aa23f6a6de46f13902952423238176","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/studygolang/GCTT/pulls/85/commits","review_comments_url":"https://api.github.com/repos/studygolang/GCTT/pulls/85/comments","review_comment_url":"https://api.github.com/repos/studygolang/GCTT/pulls/comments{/number}","comments_url":"https://api.github.com/repos/studygolang/GCTT/issues/85/comments","statuses_url":"https://api.github.com/repos/studygolang/GCTT/statuses/571d3700fc8da3127cad30e73b98c5d7c9560d60","head":{"label":"QueShengyao:master","ref":"master","sha":"571d3700fc8da3127cad30e73b98c5d7c9560d60","user":{"login":"QueShengyao","id":10654767,"avatar_url":"https://avatars2.githubusercontent.com/u/10654767?v=4","gravatar_id":"","url":"https://api.github.com/users/QueShengyao","html_url":"https://github.com/QueShengyao","followers_url":"https://api.github.com/users/QueShengyao/followers","following_url":"https://api.github.com/users/QueShengyao/following{/other_user}","gists_url":"https://api.github.com/users/QueShengyao/gists{/gist_id}","starred_url":"https://api.github.com/users/QueShengyao/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/QueShengyao/subscriptions","organizations_url":"https://api.github.com/users/QueShengyao/orgs","repos_url":"https://api.github.com/users/QueShengyao/repos","events_url":"https://api.github.com/users/QueShengyao/events{/privacy}","received_events_url":"https://api.github.com/users/QueShengyao/received_events","type":"User","site_admin":false},"repo":{"id":111563173,"name":"GCTT","full_name":"QueShengyao/GCTT","owner":{"login":"QueShengyao","id":10654767,"avatar_url":"https://avatars2.githubusercontent.com/u/10654767?v=4","gravatar_id":"","url":"https://api.github.com/users/QueShengyao","html_url":"https://github.com/QueShengyao","followers_url":"https://api.github.com/users/QueShengyao/followers","following_url":"https://api.github.com/users/QueShengyao/following{/other_user}","gists_url":"https://api.github.com/users/QueShengyao/gists{/gist_id}","starred_url":"https://api.github.com/users/QueShengyao/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/QueShengyao/subscriptions","organizations_url":"https://api.github.com/users/QueShengyao/orgs","repos_url":"https://api.github.com/users/QueShengyao/repos","events_url":"https://api.github.com/users/QueShengyao/events{/privacy}","received_events_url":"https://api.github.com/users/QueShengyao/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/QueShengyao/GCTT","description":"GCTT Go中文网翻译组。","fork":true,"url":"https://api.github.com/repos/QueShengyao/GCTT","forks_url":"https://api.github.com/repos/QueShengyao/GCTT/forks","keys_url":"https://api.github.com/repos/QueShengyao/GCTT/keys{/key_id}","collaborators_url":"https://api.github.com/repos/QueShengyao/GCTT/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/QueShengyao/GCTT/teams","hooks_url":"https://api.github.com/repos/QueShengyao/GCTT/hooks","issue_events_url":"https://api.github.com/repos/QueShengyao/GCTT/issues/events{/number}","events_url":"https://api.github.com/repos/QueShengyao/GCTT/events","assignees_url":"https://api.github.com/repos/QueShengyao/GCTT/assignees{/user}","branches_url":"https://api.github.com/repos/QueShengyao/GCTT/branches{/branch}","tags_url":"https://api.github.com/repos/QueShengyao/GCTT/tags","blobs_url":"https://api.github.com/repos/QueShengyao/GCTT/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/QueShengyao/GCTT/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/QueShengyao/GCTT/git/refs{/sha}","trees_url":"https://api.github.com/repos/QueShengyao/GCTT/git/trees{/sha}","statuses_url":"https://api.github.com/repos/QueShengyao/GCTT/statuses/{sha}","languages_url":"https://api.github.com/repos/QueShengyao/GCTT/languages","stargazers_url":"https://api.github.com/repos/QueShengyao/GCTT/stargazers","contributors_url":"https://api.github.com/repos/QueShengyao/GCTT/contributors","subscribers_url":"https://api.github.com/repos/QueShengyao/GCTT/subscribers","subscription_url":"https://api.github.com/repos/QueShengyao/GCTT/subscription","commits_url":"https://api.github.com/repos/QueShengyao/GCTT/commits{/sha}","git_commits_url":"https://api.github.com/repos/QueShengyao/GCTT/git/commits{/sha}","comments_url":"https://api.github.com/repos/QueShengyao/GCTT/comments{/number}","issue_comment_url":"https://api.github.com/repos/QueShengyao/GCTT/issues/comments{/number}","contents_url":"https://api.github.com/repos/QueShengyao/GCTT/contents/{+path}","compare_url":"https://api.github.com/repos/QueShengyao/GCTT/compare/{base}...{head}","merges_url":"https://api.github.com/repos/QueShengyao/GCTT/merges","archive_url":"https://api.github.com/repos/QueShengyao/GCTT/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/QueShengyao/GCTT/downloads","issues_url":"https://api.github.com/repos/QueShengyao/GCTT/issues{/number}","pulls_url":"https://api.github.com/repos/QueShengyao/GCTT/pulls{/number}","milestones_url":"https://api.github.com/repos/QueShengyao/GCTT/milestones{/number}","notifications_url":"https://api.github.com/repos/QueShengyao/GCTT/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/QueShengyao/GCTT/labels{/name}","releases_url":"https://api.github.com/repos/QueShengyao/GCTT/releases{/id}","deployments_url":"https://api.github.com/repos/QueShengyao/GCTT/deployments","created_at":"2017-11-21T14:58:32Z","updated_at":"2017-11-21T12:38:04Z","pushed_at":"2017-11-30T16:55:55Z","git_url":"git://github.com/QueShengyao/GCTT.git","ssh_url":"git@github.com:QueShengyao/GCTT.git","clone_url":"https://github.com/QueShengyao/GCTT.git","svn_url":"https://github.com/QueShengyao/GCTT","homepage":"https://studygolang.com/gctt","size":1089,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":null,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"studygolang:master","ref":"master","sha":"f8c73631c03a113ae17753086b66a685adc70b1a","user":{"login":"studygolang","id":3772217,"avatar_url":"https://avatars3.githubusercontent.com/u/3772217?v=4","gravatar_id":"","url":"https://api.github.com/users/studygolang","html_url":"https://github.com/studygolang","followers_url":"https://api.github.com/users/studygolang/followers","following_url":"https://api.github.com/users/studygolang/following{/other_user}","gists_url":"https://api.github.com/users/studygolang/gists{/gist_id}","starred_url":"https://api.github.com/users/studygolang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/studygolang/subscriptions","organizations_url":"https://api.github.com/users/studygolang/orgs","repos_url":"https://api.github.com/users/studygolang/repos","events_url":"https://api.github.com/users/studygolang/events{/privacy}","received_events_url":"https://api.github.com/users/studygolang/received_events","type":"Organization","site_admin":false},"repo":{"id":110936509,"name":"GCTT","full_name":"studygolang/GCTT","owner":{"login":"studygolang","id":3772217,"avatar_url":"https://avatars3.githubusercontent.com/u/3772217?v=4","gravatar_id":"","url":"https://api.github.com/users/studygolang","html_url":"https://github.com/studygolang","followers_url":"https://api.github.com/users/studygolang/followers","following_url":"https://api.github.com/users/studygolang/following{/other_user}","gists_url":"https://api.github.com/users/studygolang/gists{/gist_id}","starred_url":"https://api.github.com/users/studygolang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/studygolang/subscriptions","organizations_url":"https://api.github.com/users/studygolang/orgs","repos_url":"https://api.github.com/users/studygolang/repos","events_url":"https://api.github.com/users/studygolang/events{/privacy}","received_events_url":"https://api.github.com/users/studygolang/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/studygolang/GCTT","description":"GCTT Go中文网翻译组。","fork":false,"url":"https://api.github.com/repos/studygolang/GCTT","forks_url":"https://api.github.com/repos/studygolang/GCTT/forks","keys_url":"https://api.github.com/repos/studygolang/GCTT/keys{/key_id}","collaborators_url":"https://api.github.com/repos/studygolang/GCTT/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/studygolang/GCTT/teams","hooks_url":"https://api.github.com/repos/studygolang/GCTT/hooks","issue_events_url":"https://api.github.com/repos/studygolang/GCTT/issues/events{/number}","events_url":"https://api.github.com/repos/studygolang/GCTT/events","assignees_url":"https://api.github.com/repos/studygolang/GCTT/assignees{/user}","branches_url":"https://api.github.com/repos/studygolang/GCTT/branches{/branch}","tags_url":"https://api.github.com/repos/studygolang/GCTT/tags","blobs_url":"https://api.github.com/repos/studygolang/GCTT/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/studygolang/GCTT/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/studygolang/GCTT/git/refs{/sha}","trees_url":"https://api.github.com/repos/studygolang/GCTT/git/trees{/sha}","statuses_url":"https://api.github.com/repos/studygolang/GCTT/statuses/{sha}","languages_url":"https://api.github.com/repos/studygolang/GCTT/languages","stargazers_url":"https://api.github.com/repos/studygolang/GCTT/stargazers","contributors_url":"https://api.github.com/repos/studygolang/GCTT/contributors","subscribers_url":"https://api.github.com/repos/studygolang/GCTT/subscribers","subscription_url":"https://api.github.com/repos/studygolang/GCTT/subscription","commits_url":"https://api.github.com/repos/studygolang/GCTT/commits{/sha}","git_commits_url":"https://api.github.com/repos/studygolang/GCTT/git/commits{/sha}","comments_url":"https://api.github.com/repos/studygolang/GCTT/comments{/number}","issue_comment_url":"https://api.github.com/repos/studygolang/GCTT/issues/comments{/number}","contents_url":"https://api.github.com/repos/studygolang/GCTT/contents/{+path}","compare_url":"https://api.github.com/repos/studygolang/GCTT/compare/{base}...{head}","merges_url":"https://api.github.com/repos/studygolang/GCTT/merges","archive_url":"https://api.github.com/repos/studygolang/GCTT/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/studygolang/GCTT/downloads","issues_url":"https://api.github.com/repos/studygolang/GCTT/issues{/number}","pulls_url":"https://api.github.com/repos/studygolang/GCTT/pulls{/number}","milestones_url":"https://api.github.com/repos/studygolang/GCTT/milestones{/number}","notifications_url":"https://api.github.com/repos/studygolang/GCTT/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/studygolang/GCTT/labels{/name}","releases_url":"https://api.github.com/repos/studygolang/GCTT/releases{/id}","deployments_url":"https://api.github.com/repos/studygolang/GCTT/deployments","created_at":"2017-11-16T07:10:44Z","updated_at":"2017-12-05T06:32:36Z","pushed_at":"2017-12-05T10:21:15Z","git_url":"git://github.com/studygolang/GCTT.git","ssh_url":"git@github.com:studygolang/GCTT.git","clone_url":"https://github.com/studygolang/GCTT.git","svn_url":"https://github.com/studygolang/GCTT","homepage":"https://studygolang.com/gctt","size":3527,"stargazers_count":139,"watchers_count":139,"language":"Shell","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":59,"mirror_url":null,"archived":false,"open_issues_count":14,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0"},"forks":59,"open_issues":14,"watchers":139,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/studygolang/GCTT/pulls/85"},"html":{"href":"https://github.com/studygolang/GCTT/pull/85"},"issue":{"href":"https://api.github.com/repos/studygolang/GCTT/issues/85"},"comments":{"href":"https://api.github.com/repos/studygolang/GCTT/issues/85/comments"},"review_comments":{"href":"https://api.github.com/repos/studygolang/GCTT/pulls/85/comments"},"review_comment":{"href":"https://api.github.com/repos/studygolang/GCTT/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/studygolang/GCTT/pulls/85/commits"},"statuses":{"href":"https://api.github.com/repos/studygolang/GCTT/statuses/571d3700fc8da3127cad30e73b98c5d7c9560d60"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"rxcai"}}