{"action":"created","issue":{"url":"https://api.github.com/repos/paked/engi/issues/53","labels_url":"https://api.github.com/repos/paked/engi/issues/53/labels{/name}","comments_url":"https://api.github.com/repos/paked/engi/issues/53/comments","events_url":"https://api.github.com/repos/paked/engi/issues/53/events","html_url":"https://github.com/paked/engi/issues/53","id":115050860,"number":53,"title":"Multithreading","user":{"login":"EtienneBruines","id":3962174,"avatar_url":"https://avatars.githubusercontent.com/u/3962174?v=3","gravatar_id":"","url":"https://api.github.com/users/EtienneBruines","html_url":"https://github.com/EtienneBruines","followers_url":"https://api.github.com/users/EtienneBruines/followers","following_url":"https://api.github.com/users/EtienneBruines/following{/other_user}","gists_url":"https://api.github.com/users/EtienneBruines/gists{/gist_id}","starred_url":"https://api.github.com/users/EtienneBruines/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/EtienneBruines/subscriptions","organizations_url":"https://api.github.com/users/EtienneBruines/orgs","repos_url":"https://api.github.com/users/EtienneBruines/repos","events_url":"https://api.github.com/users/EtienneBruines/events{/privacy}","received_events_url":"https://api.github.com/users/EtienneBruines/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/paked/engi/labels/enhancement","name":"enhancement","color":"84b6eb"},{"url":"https://api.github.com/repos/paked/engi/labels/feature","name":"feature","color":"207de5"},{"url":"https://api.github.com/repos/paked/engi/labels/question","name":"question","color":"cc317c"}],"state":"open","locked":false,"assignee":{"login":"paked","id":8407370,"avatar_url":"https://avatars.githubusercontent.com/u/8407370?v=3","gravatar_id":"","url":"https://api.github.com/users/paked","html_url":"https://github.com/paked","followers_url":"https://api.github.com/users/paked/followers","following_url":"https://api.github.com/users/paked/following{/other_user}","gists_url":"https://api.github.com/users/paked/gists{/gist_id}","starred_url":"https://api.github.com/users/paked/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/paked/subscriptions","organizations_url":"https://api.github.com/users/paked/orgs","repos_url":"https://api.github.com/users/paked/repos","events_url":"https://api.github.com/users/paked/events{/privacy}","received_events_url":"https://api.github.com/users/paked/received_events","type":"User","site_admin":false},"milestone":null,"comments":13,"created_at":"2015-11-04T13:23:41Z","updated_at":"2015-11-08T17:25:21Z","closed_at":null,"body":"As Go is such a nice language to do multithreading in, and most games lack multithreading, it'd be nice if we supported it. \r\n\r\nCurrently, each frame, we are iterating over all `System`s, and iterating over all `Entity`s \"in\" those `System`s. \r\n\r\nI'm not sure if we can safely multithread multiple `System`s at once, but we could easily multithread the iteration over `Entity`s?\r\n\r\n### Current implementation\r\n```go\r\n    for _, system := range w.Systems() {\r\n\t\tif headless && system.SkipOnHeadless() {\r\n\t\t\tcontinue // so skip it\r\n\t\t}\r\n\r\n\t\tsystem.Pre()\r\n\t\tfor _, entity := range system.Entities() {\r\n\t\t\tif w.paused {\r\n\t\t\t\tok := entity.GetComponent(&unp)\r\n\t\t\t\tif !ok {\r\n\t\t\t\t\tcontinue // so skip it\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif entity.Exists {\r\n\t\t\t\tsystem.Update(entity, dt)\r\n\t\t\t}\r\n\t\t}\r\n\t\tsystem.Post()\r\n\t}\r\n```\r\n\r\n### Proposed implementation\r\n```go\r\n    for _, system := range w.Systems() {\r\n\t\tif headless && system.SkipOnHeadless() {\r\n\t\t\tcontinue // so skip it\r\n\t\t}\r\n\r\n\t\tentities := system.Entities()\r\n\r\n\t\tsystem.Pre()\r\n                \r\n        // It's not always faster to multithread; so in this case we're not going to\r\n\t\tif len(entities) < 2*runtime.NumCPU() {\r\n\t\t\tfor _, ent := range entities {\r\n\t\t\t\tsystem.Update(ent, dt)\r\n\t\t\t}\r\n            system.Post()\r\n\t\t\tcontinue // with other Systems\r\n\t\t}\r\n\r\n\t\tentityChannel := make(chan *Entity)\r\n\t\twg := sync.WaitGroup{}\r\n\r\n\t\t// Launch workers\r\n\t\tfor i := 0; i < runtime.NumCPU(); i++ {\r\n\t\t\tgo func() {\r\n\t\t\t\tfor ent := range entityChannel {\r\n\t\t\t\t\tsystem.Update(ent, dt)\r\n\t\t\t\t\twg.Done()\r\n\t\t\t\t}\r\n\t\t\t}()\r\n\t\t}\r\n\r\n        // Give them something to do\r\n\t\tfor _, entity := range entities {\r\n\t\t\tif w.paused {\r\n\t\t\t\tok := entity.GetComponent(&unp)\r\n\t\t\t\tif !ok {\r\n\t\t\t\t\tcontinue // so skip it\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif entity.Exists {\r\n\t\t\t\twg.Add(1)\r\n\t\t\t\tentityChannel <- entity\r\n\t\t\t}\r\n\t\t}\r\n\r\n        // Wait until they're done, before continuing to other Systems\r\n\t\twg.Wait()\r\n\t\tclose(entityChannel)\r\n\r\n\t\tsystem.Post()\r\n\t}\r\n```\r\n\r\nI know it's a bit more code than the original implementation, but it sure is efficient. "},"comment":{"url":"https://api.github.com/repos/paked/engi/issues/comments/154842634","html_url":"https://github.com/paked/engi/issues/53#issuecomment-154842634","issue_url":"https://api.github.com/repos/paked/engi/issues/53","id":154842634,"user":{"login":"EtienneBruines","id":3962174,"avatar_url":"https://avatars.githubusercontent.com/u/3962174?v=3","gravatar_id":"","url":"https://api.github.com/users/EtienneBruines","html_url":"https://github.com/EtienneBruines","followers_url":"https://api.github.com/users/EtienneBruines/followers","following_url":"https://api.github.com/users/EtienneBruines/following{/other_user}","gists_url":"https://api.github.com/users/EtienneBruines/gists{/gist_id}","starred_url":"https://api.github.com/users/EtienneBruines/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/EtienneBruines/subscriptions","organizations_url":"https://api.github.com/users/EtienneBruines/orgs","repos_url":"https://api.github.com/users/EtienneBruines/repos","events_url":"https://api.github.com/users/EtienneBruines/events{/privacy}","received_events_url":"https://api.github.com/users/EtienneBruines/received_events","type":"User","site_admin":false},"created_at":"2015-11-08T17:25:21Z","updated_at":"2015-11-08T17:25:21Z","body":"I am amazed by the results:\r\n\r\n```\r\nBenchmarkWorldWorkersOne-4  \t  100000\t     55365 ns/op\r\nBenchmarkWorldWorkersTwo-4  \t  100000\t     49654 ns/op\r\nBenchmarkWorldWorkersFour-4 \t  100000\t     49153 ns/op\r\nBenchmarkWorldWorkersEight-4\t  100000\t     60911 ns/op\r\nBenchmarkWorldLegacy-4      \t  100000\t     38713 ns/op\r\n```\r\n\r\nI truly expected a different outcome. I'm investigating as to how this is even possible. "}}