2

I'm currently developing an application which relies on multiple sockets listening for chat messages. When the messages come in, they're passed off to a bot that's associated with their channels. Because of the large number of channels this bot is associated with, it's highly inefficient to create a thread for each bot.

Ideally, what I'm looking for is to fire off a task, that will run within a task pool to process messages for each bot. I'd like to have a thread pool of say 30-100 threads running processing messages concurrently, but only 1 thread tied to a specific bot (or socket). I've read a bit about the Task Parallel Library, but I'm confused how to lock to a specific context.

Everything starts here:

IrcConnection.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, RecieveComplete, state);

//When a message comes in, it calls RecieveComplete, which invokes an event handler:

UserMessageRecieved?.Invoke(this, new UserMessageEventArgs(userMessage));

//And the event handler:
public async void bot_UserMessageRecieved(object sender, UserMessageEventArgs e)

Right now, multiple threads can be running concurrently accessing a single bot context. What would be a good solution to prevent this from happening? Is the TPL the correct way to go for this project?

1

Based on your question, you need an agent to process multiple process to send and receive messages in parallel, but processing these messages has to have asynchronous behavior, because you are dealing with I/O. Most I/O operations (including TCP socket) is usually blocking, therefore having async implemented is the best option.

But combining parallel with async operation is not an easy task if you use .NET EAP (event asynchronous pattern), that you have shown in your question. I know the .NET EAP model, because you are using Beginxxx and Endxxx pattern in the method. This in turn makes async-await usage more difficult. It is difficult, because then all of the async and await operations must encapsulate the Beginxxx and Receivexx (or Endxxx) method pair.

You should be aware that the EAP model is now considered legacy async model in .NET 4.5 and above, just check on the MSDN Library links below.

For parallel programming, it is available in NET TPL (Task Parallel Library) model. This .NET TPL only describes parallel programming. If you are going to use async-await, you need to check the .NET TAP (Task Asynchrony Pattern) model, and this is why .NET TAP is not exactly the same as .NET TPL.

I suggest you to use the existing .NET 4.5 (and above) Socket API in System.Net.Sockets (for example, just look at the TcpListener's methods that has Async suffix) instead, and then combine each execution of the async method in a parallel execution.

Second, don't use a single context for your bot. Having parallel programming means you should be aware that you are going to have multiple execution contexts running separately. Having just one context is then will increase difficulties, because you should manage states for different message conversations. But your mileage may vary, though.

Last suggestions: there's no single bullet for any concurrency model.

For more information about .NET EAP, please visit: https://msdn.microsoft.com/en-us/library/ms228969(v=vs.110).aspx

For more information about .NET TAP, please visit: https://msdn.microsoft.com/en-us/library/hh873175(v=vs.110).aspx

For more information about .NET TPL, please visit: https://msdn.microsoft.com/en-us/library/dd460693(v=vs.110).aspx

UPDATE 1 (based on the comments):

Task scheduler? Yes, for task scheduler/sync context in TPL, please visit sample of TaskScheduler in the .NET TPL: https://msdn.microsoft.com/en-us/library/system.threading.tasks.taskscheduler(v=vs.110).aspx

But be careful when using this class, please ensure that you have added CancellationToken support in all of your Task creation, otherwise you'll get unpredictable behavior if your process is locked/timed out.

If you want to have more control on how you want the sequencing and granularity of the max number of parallel operations, you can then combine parallel programming in .NET TPL using your customized parallel execution. For example, you can run the Parallel.For with the additional ParallelLoopState and ParallelOptions.

For example: see the documentation of Parallel.For with ParallelOptions usage at: https://msdn.microsoft.com/en-us/library/dd784105(v=vs.110).aspx

  • Thanks for your reply! The main issue I have is the processing for each bot: There is a lot of complexity between settings/running polls/current state, that I'd like to avoid unnecessary locking all over the place for each command. I thought about using a semaphore slim that I can call at the beginning of the event handler. It seems like I should be doing this in the task scheduler/sync context though. – FrankerZ Feb 26 '17 at 18:39
  • The EAP methods that I use, only fire off the initial async task using invoke. I believe changing this using the task scheduler is not going to change much. As far as a "single context" for my bot, I don't want it to seem like 1 context. It would be ~ 2000 contexts, that all multiple messages to be running concurrently for multiple channels, but only 1 message at a time for each context (or channel). – FrankerZ Feb 26 '17 at 18:42
  • @FrankerZ I have modified my answer above to answer your comment. – eriawan Feb 26 '17 at 19:20
  • @FrankerZ please confirm :) if you still need more explanation about my answer, I'd like to know. If you find my answer is helpful, please mark it as an answer because it will benefit for others as well. – eriawan Feb 28 '17 at 8:22
  • I'm still confused at where to go from here. Without seeing some code on how I'm able to sync the contexts, I'm left in my original position. I'm confused at how I should create a TaskScheduler or SynchronizationContext to do this. – FrankerZ Feb 28 '17 at 9:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.