Reputation: 2973
Regarding the right worker method signature I need to understand the following:
Task
instead of void
for Worker
method (if going sync)? Wait()
) on the Worker
method (if going sync)? Worker
method when marked as returning Task
object (both if going sync/async)? Worker
method should be, given the work it completes is long-running CPU/IO-bound work? Should I follow this recommendation (if going mixed/async)?Note
Despite the cpu-bound code, there's a choice to call async versions of io-bound methods (sql queries). So it may be all sync or partially async. As for the nature of code in the Worker
method.
public class LoopingService
{
private CancellationTokenSource cts;
// ..
void Worker(CancellationToken cancellationToken)
{
while(!cancellationToken.IsCancellationRequested)
{
// mixed, CPU/IO-bound code
try {
// sql query (can be called either as sync/async)
var lastId = documentService.GetLastDocument().Id;
// get next document from a public resource (third-party code, sync)
// can be moved to a web api
var document = thirdPartyDocumentService.GetNextDocument(lastId);
// apply different processors in parallel
var tasksList = new List<Task>();
foreach(var processor in documentService.Processors) {
// each processor checks if it's applicable
// which may include xml-parsing, additional db calls, regexes
// if it's applicable then document data is inserted into the db
var task = new Task(() => processor.Process(document));
tasksList.Add(task);
task.Start();
}
// or
// var tasksList = documentService.ProcessParallel(document);
Task.WaitAll(tasksList.ToArray(), cancellationToken);
}
catch(Exception ex) {
logger.log(ex);
}
}
}
public void Start()
{
this.cts = new CancellationTokenSource();
Task.Run(() => this.Worker(cts.Token));
}
public void Stop()
{
this.cts.Cancel();
this.cts.Dispose();
}
}
Upvotes: 1
Views: 56
Reputation: 169330
is there a point in returning Task instead of void for Worker method?
If Worker
is a truly asynchronous method it should return a Task
for you to be able to await it. If it's just a synchronous method runnning on a background thread there is no point of changing the return type from void
provided that the method is not supposed to return anything.
what should be the return value of
Worker
method when marked as returningTask
object?
Nothing. Provided that the method is asynchronous and marked as async
with a return type of Task
, it shouldn't return any value:
async Task Worker(CancellationToken cancellationToken) { ... }
Note that there is no point of defining the method as async
unless you actually use the await
keyword in it.
what signature and body of
Worker
method should be given the work it completes is long-running CPU/IO-bound work? Should I follow this recommendation?
Yes, probably. If you for some reason are doing both asynchronous and synchronous (CPU-bound) work in the same method, you should prefer to using an asynchronous signature but not wrap the synchronous stuff in Task.Run
. Then your service would look something like this:
public class LoopingService
{
private CancellationTokenSource cts;
async Task Worker(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
await ...
}
}
public async Task Start()
{
this.cts = new CancellationTokenSource();
await this.Worker(cts.Token).ConfigureAwait(false);
}
public void Stop()
{
this.cts.Cancel();
this.cts.Dispose();
}
}
Ideally your method should be either asynchronous or CPU-bound but not both though.
Upvotes: 3