views:

120

answers:

7

I'm currently using Retlang for message-based multithreading in .NET, which is a great library. I've got no explicit locks anymore, every thread is doing its own business, managing its part of the application and communicating with other threads via messages.

I now have to implement a feature of my application that could also have its own publisher/subscriber thread. The only problem is that this thread will actually do very few work. It's expected to receive a message from a publisher every 10 minutes or so. When a message is received, it will do some work but nothing that should take more than a few hundreds milliseconds.

So I started wondering if having a thread sleeping 99.9% of the time was actually a good choice. There's the thread pool for this kind of operation but since I have no control over which thread my messages will be received, I have to resort to ugly, error-prone locks.

My question is: is it really a problem, resource-wise, to leave a thread idle, waiting the vast majority of time? Using shared multithreading after using a good message-based architecture feels like going back in time, plus it will be the only part of the application with locks. But I keep wondering "Am I doing something wrong here?" with this thread.

Edit: thank you everyone, after reading every of your answers I decided that another thread wasn't so much a problem. My application will stay coherent with only message-based multithreading and if I really have a performance problem (but that shouldn't be the case) I'll investigate further.

+2  A: 

This sounds like an ideal scenario to use a Task. They use the thread pool by default underneath, but have a much more evolved API.

Stephen Cleary
Except that this would qualify for a good candidate for a task generated with the LongRunning hint (to prevent thread starvation in the ThreadPool). However, if you do that, you're going to be generating a dedicated thread (provided you use the default scheduler), so Task won't provide any advantages other than a potentially cleaner API.
Reed Copsey
Um, no; I meant creating a `Task` for each work to do. So each `Task` would be very short-lived.
Stephen Cleary
+2  A: 

I would actually argue that using the ThreadPool for a thread that's sleeping most of the time is a poor design choice -

Having a single thread sleeping (or, better, waiting on an event) has very little overhead in your application. The main disadvantage of using a dedicated thread is that thread will need to have it's own stack allocated, so you'll use a bit of extra memory vs. a threadpool thread.

Reed Copsey
I'm not worried about a little extra memory, memory isn't a problem for this kind of application. It was the potential impact of another thread on the application I was mainly worried about.
Julien Lebosquain
A: 

I think this is fundamentally a question of optimization. Is your application having a performance problem (specifically a memory problem)? If not, then go ahead and leave the thread idle and keep your code cleaner. Explore other options once you have a real reason.

C. Ross
+1  A: 

Can't you use Retlang's PoolFiber for this? It isn't backed by a dedicated thread like ThreadFiber but instead by the .Net threadpool. Which means you can keep using the same Retlang semantics you are using throughout your application without keeping an idle thread.

Ronald Wildenberg
I already knew about it and I was planning to use it. However it still produces message on a random thread pool thread so the work there will have to synchronize with existing objects, shared between works on this thread but not with the others).
Julien Lebosquain
I see the problem. This type of synchronization is exactly what you are trying to prevent. But shouldn't direct access to these existing objects be hidden from you through other fibers? I.e. shouldn't you just use messages again to communicate with the fiber(s) responsible for updating these objects?
Ronald Wildenberg
This is the core of my problem. The thread I'm having problem with is an independent part of the application, that will of course communicate with other fibers but which also have its own objects, only used by this very fiber/thread and not exposed outside.
Julien Lebosquain
A: 

I would say that having a dedicated thread for receiving these messages fine. I might even goes as far as saying that it would be the preferred method. It is not like you are just creating threads willy-nilly or anything like that. We are talking about one extra thread here and it will not consume a lot resources (maybe a little stack space). The advantage of not having to worry about the additional synchronization of shared state (aside from the message passing of course) trumps the disadvantages in my opinion.

Brian Gideon
A: 

You should consider using F#. It is great for programming logically-single-threaded-agents without burning threads (e.g. agents can hop about the ThreadPool, but still respond to messages in a serialized fashion, and an arriving message at their mailbox wakes them up and schedules ThreadPool work).

http://blogs.msdn.com/b/dsyme/archive/2010/02/15/async-and-parallel-design-patterns-in-f-part-3-agents.aspx

Brian
The whole application is already in C#, and while I'm eager to learn F#, I don't currently have the time to learn it and I don't think implementing a very small part of the application in another language is worth it.
Julien Lebosquain
+1  A: 

While each Action on the PoolFiber can execute in a separate pool thread, the actions for a particular PoolFiber execute sequentially and not in parallel, only one pool thread at a time.

The PoolFiber should do what you are looking for.

gnash
Thank you, I totally didn't realized that. You're Graham Nash, one of Retlang's authors right? Thanks for your great library! (Although I found that documentation is lacking when you have no experience of Erlang or Scala like I did.)
Julien Lebosquain
Yes, that is me. Mike Rettig did most of the work though, I just maintain it. Now that Retlang 1.0.1 is out, I will put some effort in to improve the documentation. Any areas in particular that need work?
gnash