C# 异步/等待VS任务运行:何时使用?如何使用?
好的,我希望我已经掌握了async/Wait的基本知识,但仍然有一些问题萦绕在我的脑海中 但现在这就是我所说的问题。在这个简单的例子中假设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
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;