To start, let’s define an API for an actor. The API allows messages to be sent by "enqueuing work" via one of the Enqueue methods. The "work" takes the form of delegates that either return a result or not. It can also be synchronous or asynchronous, with the intention being that the work is executed on the actor’s thread with any result relayed back to the caller via a returned task object.

An actor should ensure that messages passed to it are handled in the order in which they are received, with no two messages being processed at the same time. Essentially, it should appear that an actor has a single dedicated thread processing messages in its queue. In reality, however, a single dedicated thread would be wasteful of resources given that most of the time it would be quiescent. Therefore it is preferable to use a thread from the .NET thread pool when required. To achieve this using the TPL it is necessary that all work passed to Enqueue is scheduled to run as a Task with an implementation of TaskScheduler. Scheduling the task via Task.Factory.StartNew would mean the TaskScheduler instance returned by TaskScheduler.Current would be used. In most circumstances this would be TaskScheduler.Default which schedules tasks in parallel on the .NET thread pool but could be something else entirely. If the simpler Task.Run were used instead, then TaskScheduler.Default would always be used. Thus using either Task.Run or Task.Factory.StartNew would provide no control over when the task were run and thus tasks associated with the same actor could be run in parallel not what we want.