好的,我希望我得到了async / await的基础知识,但仍有一些问题在脑海中挥之不去。
但现在我正在谈论的问题。假设在这个简单的例子中
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()返回调用者,即返回到main函数,保存同步上下文并从那里继续执行。
首先打印Main Thread
。
然后在完成8秒后,Long Task
然后New Thread
打印出来。
这部分我得到了。我的问题在于我的申请:
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
也遇到了等待和
它应立即返回并执行下一行本身并打印Async called
甚至在SaveCaseSearch完成之前呢?
好的,如果我在大声思考它可能是control returns to the caller
。
如果我将我的调用SavCaseSearch
包含在另一个名为suppose的async / await方法
async DoWork() {....
}
直接从DoWork()
调用此CreateCase()
,然后
It will go on printing "Async called" once call to DoWork() encounters await and before it even completes ?
我是否以正确的方式思考?
有时我也会看到
之间的混淆await someAsync()
和
await Task.Run(() => someAsync())
..
它们之间的区别是什么?以及哪一个?
答案 0 :(得分:4)
我的问题出在我的申请表中:
您的代码无法编译,因为您使用的await
没有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;
}
这里也有createCase遇到等待,它应该立即返回并执行下一行本身并打印Async,甚至在SaveCaseSearch完成之前调用它?
没有。这段代码:
await saveCaseSearch(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
与此代码相同:
var saveTask = saveCaseSearchAsync(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
await saveTask;
首先,createCaseAsync
会调用saveCaseSearchAsync
。据推测,saveCaseSearchAsync
正在执行一些异步操作,因此它会将不完整的任务返回给createCaseAsync
。 createCaseAsync
然后await
该任务,导致它将一个未完成的任务返回给其调用者。
最终,saveCaseSearchAsync
将完成,这将完成它返回的任务(我在上面的代码中调用了saveTask
)。这反过来将继续执行createCaseAsync
,它将继续执行下一行并在控制台上打印“Async called”。
如果我将调用SavCaseSearch包装在另一个async / await方法
中,那就好了
您不需要包装器,因为createCaseAsync
已经返回Task
。
它们之间有什么区别?以及哪一个?
Task.Run
主要用于将阻塞工作从UI线程推送到线程池上。由于您使用的是ASP.NET,因此请勿使用Task.Run
。
答案 1 :(得分:3)
异步的第一条规则是始终使用异步或永远不要使用异步。
如果您的底层API无法处理异步,那么在上层(如ASP.NET MVC)中使用async是没有用的,因为在某些时候,当所有线程都在等待IO操作时,您将获得线程饥饿(比如DB调用。)
您的示例是混合同步和异步的经典案例。 func getFreeSpace() -> CGFloat {
do {
let fileAttributes = try NSFileManager.defaultManager().attributesOfFileSystemForPath("/")
if let size = fileAttributes[NSFileSystemFreeSize] as? CGFloat {
return size
}
} catch { }
return 0
}
调用将锁定线程直到完成。您应该使用Sleep
,因为它会释放线程,直到延迟完成。
我的建议是,首先遵循我之前提到的规则,并且仅在涉及数据库或文件调用等IO绑定操作时才开始。然后当你更好地理解异步时,你可以开始打破它,因为你可以更好地理解它可以导致什么。
(很抱歉没有直接回答您的问题,但线程是一个复杂的主题,如果您尝试直接将其全部放入,您的大脑就可以炒掉。从小处开始。)
答案 2 :(得分:1)
关于async / await和Tasks ...
之间的区别Async / Await 是用于简化代码的语法关键字,因为await关键字之前的所有内容都发生在调用线程中,而等待的所有内容都发生在任务中#39;继续。
使用TPL对任务进行设置将需要大量代码和可读性。但请注意,它下面仍在使用“任务和续集”。
此外,它们不能总是用来代替任务,比如 Task 的完成是不确定的,或者你有多个任务级别以及 TaskCompletionSource
有关更多信息,请阅读第4章和第34章;异步编程&#34;在书中#34; Writing High-Performance .NET Code&#34;作者:Ben Watson
另请注意,在内部,TPL使用.NET线程池,但通过在将线程返回池之前依次在同一线程上执行多个Tasks来更智能地执行此操作。它可以通过智能使用委托对象来实现。
答案 3 :(得分:1)
这里也有createCase正在遇到await并且应该立即返回并执行下一行本身并打印Async之前调用甚至SaveCaseSearch正确完成?
这甚至不应该编译。等待&#39;等待&#39;运算符只能在异步&#39;中使用。方法。也就是说,如果你删除等待&#39;等等。运算符,然后下一行将打印&#34; Async调用&#34;甚至在saveCaseSearch
完成之前。
我是否以正确的方式思考?
saveCaseSearch
已经是&#39; async&#39;方法,所以你不需要包装它来达到预期的效果。也就是说,如果你真的想要,可以用另一种方法包装它。
它们之间的区别是什么?和哪一个?
等待&#39; operator等待一个Task对象,这样任何一个都可以。我会选择await someAsync()
,因为它编写的代码较少。