Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 异步方法中返回和等待任务之间的区别_C#_.net_Task Parallel Library_Async Await - Fatal编程技术网

C# 异步方法中返回和等待任务之间的区别

C# 异步方法中返回和等待任务之间的区别,c#,.net,task-parallel-library,async-await,C#,.net,Task Parallel Library,Async Await,下面的方法有什么不同吗?一个比另一个好吗 public static async Task SendAsync1(string to, string subject, string htmlBody) { // ... await smtp.SendMailAsync(message); // No return statement } public static Task SendAsync2(string to, string subject, string htmlBody)

下面的方法有什么不同吗?一个比另一个好吗

public static async Task SendAsync1(string to, string subject, string htmlBody) {
  // ...
  await smtp.SendMailAsync(message);
  // No return statement
}

public static Task SendAsync2(string to, string subject, string htmlBody) {
  // ...
  return smtp.SendMailAsync(message);
}
此方法将从MVC控制器方法调用;例如:

public async Task<ActionResult> RegisterUser(RegisterViewModel model)
{
  // ...
  await Mailer.SendAsync(user.Email, subject, body);
  return View(model);
}
公共异步任务注册器(RegisterViewModel模型)
{
// ...
wait Mailer.SendAsync(user.Email,subject,body);
返回视图(模型);
}

您的第一个方法是
await
s,它将导致编译器创建一个状态机,因为一旦点击了
await
关键字,该方法将返回给调用者,并且一旦等待的部分完成,它必须从停止的点恢复

但是,由于您在等待之后没有做任何事情(没有继续),因此不需要该状态机


在这种情况下,第二种方法是首选的,您可以从中省略
async
关键字,因为您没有等待任何东西您的第一种方法
await
s将导致编译器创建一个状态机,因为一旦命中
await
关键字,该方法将返回调用方,一旦等待的部分完成,它必须从它停止的地方重新开始

但是,由于您在等待之后没有做任何事情(没有继续),因此不需要该状态机


在这种情况下,第二种方法是首选的,您可以从中省略
async
关键字,因为您不需要等待任何东西。首先,我认为示例中的代码无法编译。您需要从SendAsync2中删除'async'关键字

如果你这样做,那么这些方法可以互换使用,所以在这种情况下没有区别。我更喜欢没有async/await的

然而,在有些情况下,似乎没有区别,但区别在于细节。例如,考虑这个代码:

async Task<X> Get() 
{
     using (something) 
     {
          return await GetX();
     }
}
异步任务Get() { 使用(某物) { 返回等待GetX(); } } 如果要将此更改为:

Task<X> Get() 
{
    using (something)
    {
        return GetX(); 
    }
}
Task Get()
{
使用(某物)
{
返回GetX();
}
}
然后
using
块不再保护封装在x中的执行,并且
某物将比第一种情况下更早地被处理。重要信息,例如当
某物
是实体框架上下文时


这同样适用于
return wait
inside
try
块。

首先,我不认为您示例中的代码可以编译。您需要从SendAsync2中删除'async'关键字

如果你这样做,那么这些方法可以互换使用,所以在这种情况下没有区别。我更喜欢没有async/await的

然而,在有些情况下,似乎没有区别,但区别在于细节。例如,考虑这个代码:

async Task<X> Get() 
{
     using (something) 
     {
          return await GetX();
     }
}
异步任务Get() { 使用(某物) { 返回等待GetX(); } }
如果要将此更改为:

Task<X> Get() 
{
    using (something)
    {
        return GetX(); 
    }
}
Task Get()
{
使用(某物)
{
返回GetX();
}
}
然后
using
块不再保护封装在x中的执行,并且
某物将比第一种情况下更早地被处理。重要信息,例如当
某物
是实体框架上下文时


try
块内的
return wait
也是如此。

有两个实际区别:


  • 第二个选项不会创建允许使用
    async wait
    的状态机机制。这将对绩效产生轻微的积极影响
  • 异常处理会有点不同。将方法标记为
    async
    时,所有异常都存储在返回的任务中(来自异步部分和同步部分),并且仅在等待(或等待)任务时才会抛出。当它不是
    async
    时,来自同步部分的异常就像在任何其他方法中一样
  • 我的建议:使用第二种方法提高性能,但要注意异常和bug


    一个显示差异的示例:

    public static async Task Test()
    {
        Task pending = Task.FromResult(true);
        try
        {
            pending = SendAsync1();
        }
        catch (Exception)
        {
            Console.WriteLine("1-sync");
        }
    
        try
        {
            await pending;
        }
        catch (Exception)
        {
            Console.WriteLine("1-async");
        }
    
        pending = Task.FromResult(true);
        try
        {
            pending = SendAsync2();
        }
        catch (Exception)
        {
            Console.WriteLine("2-sync");
        }
    
        try
        {
            await pending;
        }
        catch (Exception)
        {
            Console.WriteLine("2-async");
        }
    }
    
    public static async Task SendAsync1()
    {
        throw new Exception("Sync Exception");
        await Task.Delay(10);
    }
    
    public static Task SendAsync2()
    {
        throw new Exception("Sync Exception");
        return Task.Delay(10);
    }
    
    输出:

    1-async
    2-sync
    

    有两个实际差异:


  • 第二个选项不会创建允许使用
    async wait
    的状态机机制。这将对绩效产生轻微的积极影响
  • 异常处理会有点不同。将方法标记为
    async
    时,所有异常都存储在返回的任务中(来自异步部分和同步部分),并且仅在等待(或等待)任务时才会抛出。当它不是
    async
    时,来自同步部分的异常就像在任何其他方法中一样
  • 我的建议:使用第二种方法提高性能,但要注意异常和bug


    一个显示差异的示例:

    public static async Task Test()
    {
        Task pending = Task.FromResult(true);
        try
        {
            pending = SendAsync1();
        }
        catch (Exception)
        {
            Console.WriteLine("1-sync");
        }
    
        try
        {
            await pending;
        }
        catch (Exception)
        {
            Console.WriteLine("1-async");
        }
    
        pending = Task.FromResult(true);
        try
        {
            pending = SendAsync2();
        }
        catch (Exception)
        {
            Console.WriteLine("2-sync");
        }
    
        try
        {
            await pending;
        }
        catch (Exception)
        {
            Console.WriteLine("2-async");
        }
    }
    
    public static async Task SendAsync1()
    {
        throw new Exception("Sync Exception");
        await Task.Delay(10);
    }
    
    public static Task SendAsync2()
    {
        throw new Exception("Sync Exception");
        return Task.Delay(10);
    }
    
    输出:

    1-async
    2-sync
    

    如果使用SendAsync1,可能在两个位置维护状态(通过异步/等待状态机制)的成本,但可能异步/等待状态机足够聪明,可以优化这一点…只是一个想法,但很有趣。如果使用SendAsync1,可能在两个位置维护状态(通过异步/等待状态机制)的成本,但是,也许异步/等待状态机足够聪明,可以对此进行优化…只是一个想法,但很有趣。使用/try-catch对潜在的gotcha环境进行了很好的观察!使用/try catch对潜在的gotcha周围环境进行了很好的观察!“不会创造国家机器的机械主义”-这是什么意思??你怎么知道的?你在哪里看到的?它就像隐形湖中的隐形人,我完全无法理解:(我的意思是身体上——发生了什么事?@monstro”不会创造