7

I have been working with Go recently and it occurred to me that perhaps the same CSP model could be built into a future version of .NET. I'm not simply talking about a new library that provides a channel type and a similar programming experience/model using the existing thread primitives under the hood; I mean implementing the model throughout the VM and compiler to produce executable code that is comparable to Go (I believe Go produces code that executes on an event-loop)

Is this feasible? Has it been talked about before?...or have I been 'drinking too much kool-aid'. I'm definitely way out of my depth on this one in terms of fully understanding how this might be implemented.

Eike Pierstorff
  • 31,996
  • 4
  • 43
  • 62
Myles McDonnell
  • 12,943
  • 17
  • 66
  • 116
  • One for you perhaps @EricLippert – Myles McDonnell Sep 07 '15 at 14:58
  • 2
    Go doesn't use an event loop, but a custom scheduler, just like the scheduler your OS uses for native threads (goroutines are often called 'lightweight' or 'green' threads), but which is implemented inside the Go runtime and compiled into any Go binary. – nussjustin Sep 07 '15 at 15:42
  • I'm not an expert on .NET, but `async`/`await` appear to [make it convenient to do some work asynchronously without spawning new OS threads](https://msdn.microsoft.com/en-us/library/hh191443.aspx). I doubt .NET will ever go whole hog for Go-like user-mode threading (like [fibers](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682661(v=vs.85).aspx)); just too big a change. BUT! I wouldn't sweat that. If what you know is .NET write straightforward .NET code, profile/get production metrics on the result, and selectively async-ify if/where it seems potentially useful. – twotwotwo Sep 07 '15 at 18:55
  • [A while back ago, Larry Osterman wrote](http://blogs.msdn.com/b/larryosterman/archive/2005/01/05/347314.aspx) a good bit on why user-mode scheduling is less important than it was when win32 fibers were introduced. The code to switch threads itself has become much cheaper partly just thanks to faster CPUs, while other costs haven't dropped as much (like the cache misses from the other thread working with different data/code). Just as I advise Gophers to write idiomatic Go, I'd say write regular threaded .NET unless/until the related overheads come to be a problem. – twotwotwo Sep 07 '15 at 20:00
  • 2
    The Canterbury team who produced JCSP for Java have a CCSP runtime (with a C API) which is [one of] the fastest context-switching scheduler available. It would be interesting to marry that with .Net. It uses the techniques of the Transputer from decades earlier. – Rick-777 Sep 10 '15 at 18:27

1 Answers1

4

Writing this from the perspective of someone more familiar with Go than .NET or Microsoft ecosystems generally, but trying to use sources more embedded in that world.

The Windows ecosystem does include some forms of user-mode task switching similar to what Go's scheduler does: fibers go back to Windows NT 3.51 it seems, and as a slightly more developer-friendly option, user-mode scheduling, can be used to schedule OS threads from your own code. Neither is exposed to .NET as far as I can find (1, 2).

In the post about fibers linked above, Larry Osterman explains some reasons they were no longer heavily used by 2005. Some reasons are specific quirks of fibers in the Windows API, but others apply to user-mode scheduling more generally. Executing a context switch takes microseconds these days; it just isn't a problem unless you're expecting to do hundreds of thousands of switches per second. And because of cache misses, switching to different code operating on different data might already cause delays of microseconds, even if done entirely in user mode. The gains from user threads are nice to have, but there's no reason to assume they're make-or-break.

You do have asynchronous programming tools in .NET that don't create OS-managed threads, though that's a different thing from user-managed threads. async/await make it more convenient to have an I/O operation running in the background while you do other stuff, which is similar to some uses of goroutines for asynchronous network stuff (1, 2). In .NET, people have tried to build coroutines on yield or async/await, but that does not mean it's a good idea.

I like Go plenty, but just as I advise folks to write idiomatic Go in Go, I'd say write idiomatic C#, etc. in .NET. In both cases, it's probably gonna be fine.

If you do find yourself with a problem you think might involve threads, you can always check on context switch stats to see if you really are doing enough switches to matter, then if so go back to your code to figure out how you might get things back under control. Worrying later often beats worrying too early, when you don't have working code and it's all theoretical!

Community
  • 1
  • 1
twotwotwo
  • 28,310
  • 8
  • 69
  • 56
  • This is an astonishing level of 'Not Invented Here'. Just because Go uses CSP does not mean it is not something that may be a useful alternative to what C# provides. CSP is far more than the mere low-level implementation of it. – Kenogu Labz May 22 '19 at 20:28
  • 2
    @KenoguLabz I think my response read different to you than I meant! The question as asked is explicitly _not_ about the CSP _model_ ("I'm not just talking about a...similar programming...model using the existing thread primitives"), but changing the "VM and compiler" to work more how Go's does. So my answer focused on the implementation details and their tradeoffs, and I concluded that C#'s OS-thread-centric model works well pretty often. You can always write a competing answer if you think that would help people! – twotwotwo May 22 '19 at 21:12
  • 2
    That's fair, and you're right, that is a better reading of the question at hand, I think. The only quibble I have is on it being idiomatic Go... but even there I think I see what you're saying, with regards to that not being the first tool you'd reach for in .NET in most situations. Thanks for the clarification. :) – Kenogu Labz May 23 '19 at 21:23