Skip to content

Instantly share code, notes, and snippets.

@rosado
Created July 27, 2015 18:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rosado/5bdab391fb3f9ba5b1d6 to your computer and use it in GitHub Desktop.
Save rosado/5bdab391fb3f9ba5b1d6 to your computer and use it in GitHub Desktop.
Channels (almost like in Newsqueak) again

(published May 24, 2010, blog no longer exists)

Years ago I saw a really good talk by Rob Pike about a little known language called Newsqueak. I can’t remember if I had anything more than a mild interest in concurrent programming, but that talk got my attention. I read all I could find about concurrency in Newsqueak. Fun ideas are fun to play with.

I wrote a short article about channels, which are Newsqueak’s construct for synchronization between threads. I tried to emulate behavior of channels in C# via locking and signaling. I was aware that there probably is no 1:1 mapping between what Newsqueak calls processes and managed threads in .NET (though I’m not sure to this day how many processes could Newsqueak spawn before bringing machine to a halt) but the exercise was fun enough to do it anyway.

Now, this was long enough ago, that C# didn’t have syntax for lambdas and was missing all the concurrency goodness that .NET 4 brings. I decided to update the code, expecting it to be a 5 minute operation. It took a bit longer.

Code to be upgraded consisted of 2 projects: a Channel<t> class and a nice example adapted from the presentation mentioned above. Implementation of channel didn’t need any changes, but the example (an interesting take on Eratosthenes prime sieve) was spawning System.Threading.Threads. Replacing occurrences of

#!csharp
new Thread(foo).Start();

with

#!csharp
Task.Factory.StartNew(foo);

resulted in this:

The Y axis on the graph is the number of contentions. In other words, the program spend 94% of its time on synchronization. A disaster.

Fixing this took me a couple of minutes but it is not obvious. The prime sieve works by starting new Task for filtering out multiplies of a certain number. The filters are chained together and every integer which comes out at the end, has to go through all of them. Newly discovered primes cause a new filter to be added; making sure multiplies of this new prime get rejected from now on.

New filters are chugging along, each in a new Task created via a factory as shown above. So why all the contention?

Tasks are scheduled on the thread pool and apparently the default hints passed to the scheduler are not enough. We can fix that by being more explicit about the nature of our task:

#!csharp
Task.Factory.StartNew(Filter, arg, TaskCreationOptions.LongRunning);

our filters are kept alive as long as the program is running, therefore the TaskCreationOptions.LongRunning.

While entertaining, the prime sieve is obviously abusing Tasks and managed threads; cost of synchronization is greater than the cost of the computation performed in each thread. But finding out the differences between System.Threading.Thread and System.Threading.Tasks.Task, the new recommended method of spawning new threads from .NET 4.0, may come in handy. Especially if one decides to make some changes in older code.

I pushed the revised version on github: prime-sieve-cs

Side note: I’ve been meaning to have a look at Go language, which I know expands on themes present in Newsqueak. I finally found some time and want to write down some thoughts on Go, Clojure and other things.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment