Warm tip: This article is reproduced from serverfault.com, please click

Is this usage of Task.Run() bad practice?

发布于 2020-11-28 00:13:41

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);
        }
    }
}
Questioner
rosi97
Viewed
0
Stephen Cleary 2020-11-28 08:21:36

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.