Re: [go-nuts] How does goroutine scheduling work?

3,487 views
Skip to first unread message

Patrick Mylund Nielsen

unread,
Oct 29, 2012, 6:38:41 AM10/29/12
to Daniel Himmelein, golan...@googlegroups.com
It's an implementation detail, but right now, as far as I know, all implementations use relatively primitive cooperative scheduling, which means you may get into trouble if you're not yielding at any time, e.g. if you are doing for { ... } but not hitting any synchronization points (e.g. sleep, I/O, channel send/receive) inside it. Fortunately, that happens quite rarely in my experience, especially if you're running more than just one process (i.e. GOMAXPROCS is >1. Not that it doesn't still happen, you just don't notice.)

Improving this is high on the to-do list, and there is no reason why Go can't have preemptive scheduling.

On Mon, Oct 29, 2012 at 9:42 AM, Daniel Himmelein <daniel.h...@gmail.com> wrote:
How are goroutines scheduled within the Go runtime? Is it some cooperative scheduling like reduction-count scheduling in Erlang or is it based on time-slices and a timer (more like the traditional OS way)?

Thanks,
Daniel

--
 
 

minux

unread,
Oct 29, 2012, 6:51:24 AM10/29/12
to Patrick Mylund Nielsen, Daniel Himmelein, golan...@googlegroups.com
On Mon, Oct 29, 2012 at 6:38 PM, Patrick Mylund Nielsen <pat...@patrickmylund.com> wrote:
Improving this is high on the to-do list, and there is no reason why Go can't have preemptive scheduling.
This is http://code.google.com/p/go/issues/detail?id=543, but it is *not* high priority on the TODO list.

Daniel Himmelein

unread,
Oct 29, 2012, 6:59:54 AM10/29/12
to golan...@googlegroups.com
Thank you very much for your quick responses. I think the cooperative multitasking also has its benefits compared to a preemptive solution. This is also one reason for Erlang's speed since the VM does not need to save/restore context information at any point, which would be the case with preemtive multitasking. So this saves a lot of management overhead.
Maybe it would be a good idea to also add a reduction count for each goroutine, to make the for { } also work. Just an idea...

Patrick Mylund Nielsen

unread,
Oct 29, 2012, 7:00:14 AM10/29/12
to minux, Daniel Himmelein, golan...@googlegroups.com
You're right, coop vs. preemptive isn't a critical issue because most people won't have a problem with it in most of their usage.

What I meant when I said improving this [the scheduler] is high on the to-do list is that its deficiencies are a pretty hot topic, and most of the core team has acknowledged that there are some core issues (goroutine grouping/better context switching/less contention, improvements in coop scheduling/switch to preemptive) that need to be fixed before Go can "fulfill its destiny."

As an example, here's a bite from the FAQ: "Go's goroutine scheduler is not as good as it needs to be. In future, it should recognize such cases and optimize its use of OS threads. For now, GOMAXPROCS should be set on a per-application basis."

Patrick Mylund Nielsen

unread,
Oct 29, 2012, 7:03:31 AM10/29/12
to Daniel Himmelein, golan...@googlegroups.com, Dmitry Vyukov
Personally, I'm quite indifferent, and totally agree coop has its advantages. I think I've only been bothered by the current scheduler once -- a goroutine that didn't yield depended on another goroutine doing something -- but that was solved by simply using more than one process (plus it was pretty shoddy design on my part.)

Maybe Dmitry (cc) has an opinion on Erlang-style reduction counts?

--
 
 

Zizon Qiu

unread,
Oct 29, 2012, 7:04:02 AM10/29/12
to Daniel Himmelein, golan...@googlegroups.com
goroutines(G called internal) are push into a queue(from a M ,which like worker thread,
limited by MAXPROCESS),
and whenever a blocking operation like chan recv was called,a gosched occured.

the G will be run or not depends on the available M 
and of course the relative position inside the queue.

for details,refer to src/pkg/runtime/proc.c

Patrick Mylund Nielsen

unread,
Oct 29, 2012, 7:07:53 AM10/29/12
to Zizon Qiu, Daniel Himmelein, golan...@googlegroups.com
Fear not, that source is actually very readable: http://golang.org/src/pkg/runtime/proc.c

Also, gosched is available via runtime.Gosched() if you actually do need to occasionally yield in a for { }

--
 
 

Dmitry Vyukov

unread,
Oct 29, 2012, 7:42:13 AM10/29/12
to Patrick Mylund Nielsen, Daniel Himmelein, golang-nuts
On Mon, Oct 29, 2012 at 3:03 PM, Patrick Mylund Nielsen <pat...@patrickmylund.com> wrote:
Personally, I'm quite indifferent, and totally agree coop has its advantages. I think I've only been bothered by the current scheduler once -- a goroutine that didn't yield depended on another goroutine doing something -- but that was solved by simply using more than one process (plus it was pretty shoddy design on my part.)

Maybe Dmitry (cc) has an opinion on Erlang-style reduction counts?

I don't really know, but I suspect that Erlang had chosen reduction counts because of the stricter real-time requirements. And by that time single-core machines were more ubiquitous.
I think to typical Go workloads on modern multi-core machines asynchronous preemption makes more sense (no overheads on common path).

Daniel Himmelein

unread,
Oct 29, 2012, 7:57:46 AM10/29/12
to golan...@googlegroups.com, Patrick Mylund Nielsen, Daniel Himmelein
Interesting. Aynchronous preemption might also be a good solution. Do you already have some detailled ideas how to implement it?
The problem with the reduction count stuff is that you might have to generate code by the compiler into the binary that increments and checks the count on every method call (maybe every new stack frame).
That's also a bit wired :-).

Daniel Himmelein

unread,
Oct 29, 2012, 8:01:49 AM10/29/12
to golan...@googlegroups.com, Patrick Mylund Nielsen, Daniel Himmelein
Reduction count scheduling is much easier for an interpreting VM. Not that easy for a native language runtime. The "best" idea I had on the topic was to let the compiler generate code to increment the reduction counts for each new stack frame. But that would also not solve the "for { }" problem. Intesesting stuff :-)

Joubin Houshyar

unread,
Oct 29, 2012, 9:40:14 AM10/29/12
to golan...@googlegroups.com, Patrick Mylund Nielsen, Daniel Himmelein


On Monday, October 29, 2012 7:42:42 AM UTC-4, Dmitry Vyukov wrote:
On Mon, Oct 29, 2012 at 3:03 PM, Patrick Mylund Nielsen <pat...@patrickmylund.com> wrote:
Personally, I'm quite indifferent, and totally agree coop has its advantages. I think I've only been bothered by the current scheduler once -- a goroutine that didn't yield depended on another goroutine doing something -- but that was solved by simply using more than one process (plus it was pretty shoddy design on my part.)

Maybe Dmitry (cc) has an opinion on Erlang-style reduction counts?

I don't really know, but I suspect that Erlang had chosen reduction counts because of the stricter real-time requirements. And by that time single-core machines were more ubiquitous.
I think to typical Go workloads on modern multi-core machines asynchronous preemption makes more sense (no overheads on common path).


Reply all
Reply to author
Forward
0 new messages