Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fire multiple threads instantly in akka.net

I'm not sure if this relates more to akka.net or TPL, but I will use actors for my example to clarify the question.

The question in a nutshell: Is there any way to tell akka.net to fire more threads at once than I actually have CPU cores? Here's the sample code and the details:

I'm currently using a laptop with an 8-core processor. So let's say I'm creating 20 actors:

for (int i = 0; i < 20; i++)
{
    actorList.Add(system.ActorOf<ExampleActor>());
}

And then I'm passing a message to all of those:

actorList[0].Tell(new ExampleMessage());
Console.WriteLine("sent message to actor 1\t" + DateTime.Now.TimeOfDay);
actorList[1].Tell(new ExampleMessage());
Console.WriteLine("sent message to actor 2\t" + DateTime.Now.TimeOfDay);
...
actorList[19].Tell(new ExampleMessage());
Console.WriteLine("sent message to actor 20\t" + DateTime.Now.TimeOfDay);

All the actor does, while receiving the message is the following fake long-running process:

Console.WriteLine("Accessing slow service\t" + DateTime.Now.TimeOfDay
     + "\t" + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(60000);
Console.WriteLine("Service call was successful\t" + DateTime.Now.TimeOfDay
     + "\t" + Thread.CurrentThread.ManagedThreadId);

I also have this code in its constructor, so that I know when the actor is actually created:

public ExampleActor()
{
    Console.WriteLine("Creating " + this.Self.Path + DateTime.Now.TimeOfDay);
    ....
}

So now when I run the application I first get the "sent message to actor" line for all 20 actors - in the same millisecond. But afterwards, when the time comes from initialization, what happens is that only 8 actors are created at first.

Then, since none of the other actors have finished the job, EXACTLY 1 second later, another one is initialized (the 9th one). Another second later, we have our 10th actor created and starting the Thread.Sleep operation.

Now the question is, is there any way to tell akka.net (or the TPL below it) that I'm certain that the threads will wait for ~60 seconds for each service call? So that all 20 threads are fired at once, instead of having 8 started at once, and the full 20 threads running only after 12 seconds have passed?

like image 609
nikovn Avatar asked Oct 18 '22 15:10

nikovn


1 Answers

Akka actors run on the .Net ThreadPool by default.

You are experiencing a ThreadPool starvation where all the available threads are busy (one per CPU). When all its threads are busy, the ThreadPool adds one more thread per second to its pool.

To "solve" your issue you could increase the minimum thread count with ThreadPool.SetMinThreads. But the real fix is to not block threads (and not block actors).

If your workload is CPU bound, it would not go faster to have more actors run concurrently.

If your workload is IO bound, you should call it asynchronously:

Receive<string>(msg =>
{
    DoSomethingAsync(msg).PipeTo(Self);
}

Receive<Result>(msg =>
{
   // Process the result
}
like image 85
Jeff Cyr Avatar answered Oct 31 '22 10:10

Jeff Cyr