If the use of Task.Run
in this case justifiable ?
Currently I run this code in a WinForms app, but later on it will be used in a ASP.NET project as a HostedService
/BackgroundService
. I am not sure if this is comparable then.
After reading multiple blogs about async/await and Tasks
I feel like the Task.Run(() => ..
should be implemented in the calling method Manager.SyncLoop()
. But what if the implementation of IConnection
is truely asynchronous, wouldn't that be code smell ?
private async void button1_Click(object sender, EventArgs e)
{
// this should be handled by the BackgroudService, WinForms is used just for testing
var m = new Manager();
m.Connection = new ConnectionA();
m.ExecuteAsync();
}
}
public interface IConnection
{
Task<object> ReadAsync();
}
// assume that i cannot change this
public class SomeLib
{
private Random random = new Random();
public object SyncReading()
{
Thread.Sleep(5000);
return random.Next(); ;
}
}
public class ConnectionA : IConnection
{
private SomeLib lib = new SomeLib();
public Task<object> ReadAsync()
{
// is this usage of Task.Run ok?
var v = Task.Run(() => lib.SyncReading());
return v;
}
// this will block UI
//public Task<object> ReadAsync()
//{
// return Task.FromResult(lib.SyncReading());
//}
}
public class Manager
{
public IConnection Connection { get; set; }
public async Task ExecuteAsync()
{
await SyncLoop();
}
public async Task SyncLoop()
{
while (true)
{
var i = await Connection.ReadAsync();
await Task.Delay(2000);
}
}
}
First, can you change IConnection
? Is this synchronous implementation the primary one, or is it just one of many?
If you can change IConnection
, then make it synchronous, and you can use Task.Run
in the implementation of ExecuteAsync
.
If IConnection
needs to remain asynchronous, then I would say to implement ConnectionA.ReadAsync
synchronously. Then have the Task.Run
in ExecuteAsync
as normal. The key behind this technique is that an asynchronous (Task
-returning) signature means that the implementation may be asynchronous, not that it must be asynchronous.
I am in control of the IConnection interface. But the concrete implementation could be sync or async. Nevertheless I always want to be sure not to unnecessarily block some thread. I guess I'll go with your suggestion to implement Task.Run in the ExecuteAsync method, since I have to do it anyways (see your BackgroundService Gotcha ;) )
OK. I'd keep the
IConnection.ReadAsync
signature asynchronous, then, and just allow both asynchronous and synchronous implementations.By "keep the singature asnychronous" you mean that I should keep the async naming and ensure asynchronous execution with the
Task.Run
call inExecuteAsync
? Just for my clarification.Yes; by "asynchronous signature", I mean the
Async
suffix and aTask
(or tasklike) return type.