什么时候应该使用Task.Run()?

时间:2015-02-20 02:10:07

标签: c# asynchronous concurrency task

这两种方法之间的区别是什么:

public static int Main(string[] args)
{
    string result;  

    Task.Run(async () =>
    {
        Task<string> getStringTask = GetStringAsync();
        result = await validationsTask;
    }).Wait();

    Console.WriteLine(result);
}

public static int Main(string[] args)
{
    Task<string> getStringTask = GetStringAsync();
    getStringTask.Wait();
    string result = getStringTask.Result;

    Console.WriteLine(result);
}

我见过很多人使用第一种方法,我不知道为什么。有什么特别的优势吗?建议哪一个在控制台应用程序的主要内部等待异步方法?

2 个答案:

答案 0 :(得分:2)

  

有什么特别的优势吗?

通常使用async方法同步初始化操作,然后等待可以与await异步或与Wait()同步。 Main方法不能为async,因此您可以强行阻止Wait(),或者您可以执行Console.ReadKey()直到用户按下某个键。

Task.Run(async () => ... )操作初始化成本高时,

async非常有用。这样就可以在操作初始化时允许主线程继续。

  

建议哪一个在控制台应用程序的主要内部等待异步方法?

我会使用第二种方法的略微修改版本。您可以添加MainAsync方法并从Main调用该方法,然后您可以在其中使用await

public static async Task MainAsync()
{
    string result = await GetStringAsync();    
    Console.WriteLine(result);
}

public static int Main(string[] args)
{
    MainAsync().Wait();
}

同样使用控制台应用程序,没有死锁的风险,因为没有SynchronizationContext并且使用了默认的线程池。

答案 1 :(得分:0)

第一种方法在使用线程池线程完成asynch函数后继续执行,而第二种方法使用启动asynch函数的调用线程继续执行。

使用第二种方法,可能会出现死锁。例如(类似于从书籍CLR via C#)中提取的示例:

    public static int Main(string[] args)
    {
        Task<string> getStringTask = GetStringAsync();
        string result = getStringTask.Result; //the main thread is blocked waiting.

        Console.WriteLine(result);
    }

    public Task<string> GetStringAsync()
    {  
        // Issue the HTTP request and let the thread return from GetHttp 
        HttpResponseMessage msg = await new HttpClient().GetAsync("http://Wintellect.com/"); 
        // We never get here: The main thread is waiting for this method to finish but this method 
        // can't finish because the main thread is waiting for it to finish --> DEADLOCK! 
        return await msg.Content.ReadAsStringAsync();
    }

所以第一种方法避免了这个问题:

public static int Main(string[] args)
{
    string result;  

    Task.Run(async () =>
    {
        // We run on a thread pool thread
        Task<string> getStringTask = GetStringAsync();
        // We do get here because any thread pool thread can execute this code, we don't need the main thread.
        result = await validationsTask;
    }).Wait();

    Console.WriteLine(result);
}

另一个解决方案是使用从书中提取的ConfigureAwait(false):

  

将true传递给此方法会给您与不调用相同的行为   这个方法。但是,如果传递false,则await运算符会执行   不查询调用线程的SynchronizationContext对象,以及何时   线程池线程完成theTask,它只是完成它和   await运算符通过线程池线程执行后的代码。

    public Task<string> GetStringAsync()
    {  
         HttpResponseMessage msg = await new HttpClient().GetAsync("http://Wintellect.com/").ConfigureAwait(false); 
         // We DO get here now because a thread pool can execute this code 
// as opposed to forcing the main thread to execute it.   
         return await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
    }