C# 异步/等待VS任务运行:何时使用?如何使用?

C# 异步/等待VS任务运行:何时使用?如何使用?,c#,.net,multithreading,asynchronous,async-await,C#,.net,Multithreading,Asynchronous,Async Await,好的,我希望我已经掌握了async/Wait的基本知识,但仍然有一些问题萦绕在我的脑海中 但现在这就是我所说的问题。在这个简单的例子中假设 static void Main(string[] args) { Method(); Console.WriteLine("Main Thread"); Console.ReadLine(); } public async static void Method() { await Task.Run(new Ac

好的,我希望我已经掌握了async/Wait的基本知识,但仍然有一些问题萦绕在我的脑海中

但现在这就是我所说的问题。在这个简单的例子中假设

static void Main(string[] args)
{

    Method();

    Console.WriteLine("Main Thread");

    Console.ReadLine();

}

public async static void Method()

{

    await Task.Run(new Action(LongTask));

    Console.WriteLine("New Thread");

}

public static void LongTask()

{

    Thread.Sleep(8000);

    Console.WriteLine("Long Task");

}
在调用Method()并遇到等待8秒后,主线程仍然继续并打印
main thread

因此,相应地,Method()一旦遇到wait,就会返回给调用者,也就是这里的main函数,保存同步上下文并从那里继续执行

它首先打印
主线程

然后在完成8秒钟后,
长任务
,然后打印
新线程

这部分是我得到的。我的问题在我的申请中:

public IList<createcaseoutput> createCase(CreateCaseInput CreateCaseInput,SaveCaseSearchInput SaveCaseSearchInput)    
{
    .............
    SQL.CaseSQL.getCreateCaseParameters(CreateCaseInput, out strSPQuery, out listParam);    
    var AcctLst = rep.ExecuteStoredProcedure<createcaseoutput>(strSPQuery, listParam).ToList();

    if (!string.IsNullOrEmpty(AcctLst.ElementAt(0).o_case_seq.ToString()))

    {
        await saveCaseSearch(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
    }

    console.writeline("Async called");
    return AcctLst;    
}

public async Task<ilist<savecasesearchoutput>> saveCaseSearch(SaveCaseSearchInput SaveCaseSearchInput,Int64? case_key)

{
    ..........................
    SQL.CaseSQL.getSaveCaseSearchParameters(SaveCaseSearchInput, case_key, out strSPQuery, out listParam);

    var AcctLst = await rep.ExecuteStoredProcedureAsync<entities.case.savecasesearchoutput>(strSPQuery, listParam);

    return AcctLst;
}
然后直接从
CreateCase()
调用这个
DoWork()

一旦调用DoWork()并等待它完成之前,它将继续打印“Async called”?

我的想法正确吗

有时我也会在

await someAsync() 

等待任务。运行(()=>someAsync())


他们之间有什么区别?接下来是哪一个呢?

关于异步/等待和任务之间的区别

Async/Await是简化代码的语法关键字,因为Await关键字之前的所有事情都发生在调用线程中,而从Await开始的所有事情都发生在任务的继续中

使用TPL设置任务需要大量代码,并且可读性受到影响。但是请注意,它下面仍然使用任务和延续

此外,它们不能总是用来代替任务,例如任务的完成是不确定的,或者如果您有多个级别的任务以及TaskCompletionSource的使用

有关更多信息,请阅读Ben Watson的“异步编程”一书中的第4章“异步编程”


请注意,在内部,TPL使用.NET线程池,但这样做更智能,在将线程返回池之前,在同一线程上顺序执行多个任务。它可以通过智能地使用代理对象来实现这一点

这里createCase也遇到了wait,它应该立即返回,并在SaveCaseSearch完成之前执行下一行本身和print Async调用,对吗?

这甚至不应该编译。“await”运算符只能在“async”方法中使用。也就是说,如果删除'wait'运算符,那么下一行将在
saveCaseSearch
完成之前打印“Async called”

我的思维方式正确吗?

saveCaseSearch
已经是一种“异步”方法,因此无需包装它即可获得所需的结果。也就是说,如果你真的愿意,你可以用另一种方法来包装它

它们之间有什么区别?接下来是哪一个?


“wait”操作符等待一个任务对象,因此任何一个都可以。我会选择
等待someAsync()
,因为要编写的代码更少。

异步的第一条规则是始终使用异步或从不使用异步

如果您的底层API无法处理异步,那么在上层(如ASP.NET MVC)中使用异步是没有用的,因为在某个时候,由于所有线程都被占用等待IO操作(如DB调用),您将面临线程饥饿

您的示例是一个混合使用同步和异步的经典案例。
Sleep
调用将锁定线程,直到线程完成。您应该使用
Task.Delay
,因为它会释放线程,直到延迟完成

我给您的建议是,只需遵循我首先提到的规则,并且仅当涉及到诸如DB或文件调用之类的IO绑定操作时,即可开始。然后,当您更好地理解异步时,您可以开始打破它,因为这样您就可以更好地理解它会导致什么

(很抱歉没有直接回答您的问题,但线程是一个复杂的主题,如果您试图直接将所有内容都包含进来,您的大脑可能会崩溃。从小事做起。)

我的问题在我的申请中:

public IList<createcaseoutput> createCase(CreateCaseInput CreateCaseInput,SaveCaseSearchInput SaveCaseSearchInput)    
{
    .............
    SQL.CaseSQL.getCreateCaseParameters(CreateCaseInput, out strSPQuery, out listParam);    
    var AcctLst = rep.ExecuteStoredProcedure<createcaseoutput>(strSPQuery, listParam).ToList();

    if (!string.IsNullOrEmpty(AcctLst.ElementAt(0).o_case_seq.ToString()))

    {
        await saveCaseSearch(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
    }

    console.writeline("Async called");
    return AcctLst;    
}

public async Task<ilist<savecasesearchoutput>> saveCaseSearch(SaveCaseSearchInput SaveCaseSearchInput,Int64? case_key)

{
    ..........................
    SQL.CaseSQL.getSaveCaseSearchParameters(SaveCaseSearchInput, case_key, out strSPQuery, out listParam);

    var AcctLst = await rep.ExecuteStoredProcedureAsync<entities.case.savecasesearchoutput>(strSPQuery, listParam);

    return AcctLst;
}
您的代码无法编译,因为您正在使用
wait
而不使用
async
。更正代码为:

public async Task<IList<createcaseoutput>> createCaseAsync(CreateCaseInput CreateCaseInput,SaveCaseSearchInput SaveCaseSearchInput)    
{
  ...
  await saveCaseSearch(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
  console.writeline("Async called");
  return AcctLst;    
}
与此代码相同:

  var saveTask = saveCaseSearchAsync(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
  await saveTask;
因此,首先,
createCaseSearchAsync
将调用
saveCaseSearchAsync
。大概,
saveCaseSearchAsync
正在执行一些异步操作,因此它将向
createCaseAsync
返回一个不完整的任务
createCaseAsync
然后
等待
s该任务,这会导致它将未完成的任务返回给调用方

最后,
saveCaseSearchAsync
将完成,这将完成它返回的任务(我在上面的代码中称之为
saveTask
)。这将继续执行
createCaseAncy
,并继续执行下一行并在控制台上打印“Async called”

那么,如果我将调用SavCaseSearch包装在另一个async/await方法中,会是这样吗

您不需要包装器,因为
createCaseAsync
已返回
任务

他们之间有什么区别?接下来是哪一个


Task.Run
主要用于将阻塞工作从UI线程推送到线程池。由于您使用的是ASP.NET,因此不要使用
任务。运行

如果您试图在控制台应用程序中使用
异步
,则可能会遇到问题,除非您正确设置它,否则它可能无法正常运行。请参阅和
async
is。查看Stephen Cleary的帖子。非常有用
  var saveTask = saveCaseSearchAsync(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
  await saveTask;