{"action":"created","issue":{"url":"https://api.github.com/repos/crystal-lang/crystal/issues/5815","repository_url":"https://api.github.com/repos/crystal-lang/crystal","labels_url":"https://api.github.com/repos/crystal-lang/crystal/issues/5815/labels{/name}","comments_url":"https://api.github.com/repos/crystal-lang/crystal/issues/5815/comments","events_url":"https://api.github.com/repos/crystal-lang/crystal/issues/5815/events","html_url":"https://github.com/crystal-lang/crystal/issues/5815","id":304530265,"number":5815,"title":"Slow Concurrency","user":{"login":"Virtual-Machine","id":10815336,"avatar_url":"https://avatars3.githubusercontent.com/u/10815336?v=4","gravatar_id":"","url":"https://api.github.com/users/Virtual-Machine","html_url":"https://github.com/Virtual-Machine","followers_url":"https://api.github.com/users/Virtual-Machine/followers","following_url":"https://api.github.com/users/Virtual-Machine/following{/other_user}","gists_url":"https://api.github.com/users/Virtual-Machine/gists{/gist_id}","starred_url":"https://api.github.com/users/Virtual-Machine/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Virtual-Machine/subscriptions","organizations_url":"https://api.github.com/users/Virtual-Machine/orgs","repos_url":"https://api.github.com/users/Virtual-Machine/repos","events_url":"https://api.github.com/users/Virtual-Machine/events{/privacy}","received_events_url":"https://api.github.com/users/Virtual-Machine/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":4,"created_at":"2018-03-12T20:36:06Z","updated_at":"2018-03-13T00:24:07Z","closed_at":"2018-03-12T22:47:17Z","author_association":"NONE","body":"I have been doing performance benchmarks between Go and Crystal in order to determine why Crystal tends to run faster than Go on my machine when doing simple benchmarks but runs slower in practice when using Crystal-DB to serve web APIs.\r\n\r\nI think I found a possible cause.\r\n\r\nCrystal's concurrency appears to be much slower than Go's.\r\n\r\nBelow I took a concurrency demo from the Crystal book:\r\n\r\n```crystal\r\ndef benchmark(&block : ->) : Time::Span\r\n  t1 = Time.now\r\n  yield\r\n  t2 = Time.now\r\n  t2 - t1\r\nend\r\n\r\nchannel = Channel(Int32).new\r\n\r\n\r\nt1 = benchmark do\r\n  spawn do\r\n    puts \"Before send\"\r\n    channel.send(1)\r\n    puts \"After send\"\r\n  end\r\n\r\n  spawn do\r\n    puts \"Before receive\"\r\n    puts channel.receive\r\n    puts \"After receive\"\r\n  end\r\n\r\n  puts \"Before yield\"\r\n  Fiber.yield\r\n  puts \"After yield\"\r\nend\r\n\r\nt2 = benchmark do\r\n  puts \"Before yield\"\r\n  puts \"Before send\"\r\n  puts \"Before receive\"\r\n  puts 1\r\n  puts \"After receive\"\r\n  puts \"After send\"\r\n  puts \"After yield\"\r\nend\r\n\r\npp t1\r\npp t2\r\n\r\n```\r\n\r\nAnd replicated it with Go:\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n\t\"fmt\"\r\n\t\"time\"\r\n)\r\n\r\nfunc benchmark(block func()) float64 {\r\n\tt1 := time.Now()\r\n\tblock()\r\n\tt2 := time.Now()\r\n\treturn t2.Sub(t1).Seconds()\r\n}\r\n\r\nfunc main() {\r\n\tchannel := make(chan int)\r\n\tdirect1 := make(chan int)\r\n\tdirect2 := make(chan int)\r\n\tdirect3 := make(chan int)\r\n\r\n\tt1 := benchmark(func() {\r\n\t\tgo func() {\r\n\t\t\t<-direct1\r\n\t\t\tfmt.Println(\"Before send\")\r\n\t\t\tchannel <- 1\r\n\t\t\t<-direct2\r\n\t\t\tfmt.Println(\"After send\")\r\n\t\t\tdirect3 <- 0\r\n\t\t}()\r\n\r\n\t\tgo func() {\r\n\t\t\tval := <-channel\r\n\t\t\tfmt.Println(\"Before receive\")\r\n\t\t\tfmt.Println(val)\r\n\t\t\tfmt.Println(\"After receive\")\r\n\t\t\tdirect2 <- 0\r\n\t\t}()\r\n\r\n\t\tfmt.Println(\"Before yield\")\r\n\t\tdirect1 <- 0\r\n\t\t<-direct3\r\n\t\tfmt.Println(\"After yield\")\r\n\t})\r\n\r\n\tt2 := benchmark(func() {\r\n\t\tfmt.Println(\"Before yield\")\r\n\t\tfmt.Println(\"Before send\")\r\n\t\tfmt.Println(\"Before receive\")\r\n\t\tfmt.Println(1)\r\n\t\tfmt.Println(\"After receive\")\r\n\t\tfmt.Println(\"After send\")\r\n\t\tfmt.Println(\"After yield\")\r\n\t})\r\n\r\n\tfmt.Printf(\"t1: %f\\n\", t1)\r\n\tfmt.Printf(\"t2: %f\\n\", t2)\r\n}\r\n\r\n```\r\n\r\nPerformance on my machine (OS X El Capitan - Crystal 0.24.1 vs go 1.10):\r\n```\r\ncrystal (5 runs) --release --no-debug\r\nt1 = 0.000726  0.000832  0.000694  0.000785  0.000813\r\nt2 = 0.000019  0.000021   0.000019  0.000019  0.000021\r\n\r\ngo (5 runs) -ldflags=\"-s -w\"\r\nt1 = 0.000109  0.000099 0.000087  0.000098  0.000103\r\nt2 = 0.000023  0.000022 0.000023  0.000021  0.000024\r\n```\r\n\r\nAs you can see, the raw function calls are faster on Crystal (t2) by microseconds.\r\nBut this concurrency benchmark (t1) shows Crystal is 7-8 times slower than Go.\r\n\r\nI tried implementing Channels in the Crystal example to be more explicit about the communication similar to the Go approach to see if I could improve the performance, but it had no effect.\r\n\r\nStill not sure if this is local to my machine or not, in a few hours I can follow up with the same test run on my Linux machine."},"comment":{"url":"https://api.github.com/repos/crystal-lang/crystal/issues/comments/372505650","html_url":"https://github.com/crystal-lang/crystal/issues/5815#issuecomment-372505650","issue_url":"https://api.github.com/repos/crystal-lang/crystal/issues/5815","id":372505650,"user":{"login":"RX14","id":2788811,"avatar_url":"https://avatars0.githubusercontent.com/u/2788811?v=4","gravatar_id":"","url":"https://api.github.com/users/RX14","html_url":"https://github.com/RX14","followers_url":"https://api.github.com/users/RX14/followers","following_url":"https://api.github.com/users/RX14/following{/other_user}","gists_url":"https://api.github.com/users/RX14/gists{/gist_id}","starred_url":"https://api.github.com/users/RX14/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RX14/subscriptions","organizations_url":"https://api.github.com/users/RX14/orgs","repos_url":"https://api.github.com/users/RX14/repos","events_url":"https://api.github.com/users/RX14/events{/privacy}","received_events_url":"https://api.github.com/users/RX14/received_events","type":"User","site_admin":false},"created_at":"2018-03-13T00:24:07Z","updated_at":"2018-03-13T00:24:07Z","author_association":"MEMBER","body":"@Virtual-Machine perhaps go's `Time.new` is more optimized than ours, who knows. It'd take a profiler to tell."}}
{"actor":{"display_login":"RX14"}}