IO绑定的异步任务不是异步执行的(IO-bound async task not executes asynchronously)
我花了很多时间来理解异步编程原理。 但有一点仍不清楚。 我被这段代码搞糊涂了:
static async Task Method() { Console.WriteLine($"Method entered."); await Task.Delay(1000); Console.WriteLine($"Await 1 finished."); await Task.Delay(1000); Console.WriteLine($"Await 2 finished"); } static int Main(string[] args) { Console.WriteLine($"Main started."); return AsyncContext.Run(() => MainAsync(args)); } static async Task<int> MainAsync(string[] args) { var t = Method(); Console.WriteLine("Thread starting sleep."); Thread.Sleep(10000); Console.WriteLine("Thread stopped sleeping"); Console.WriteLine(t.IsCompleted ? "Method completed" : "Method not completed"); await t; return 0; }
结果:
Main started. Method entered. Thread starting sleep. Thread stopped sleeping Method not completed Await 1 finished. Await 2 finished
据我所知,当主线程处于休眠状态时,应执行来自Method的IO绑定操作(导致Task.Delay模拟IO)并按顺序中断主线程以继续执行方法代码。 所以我希望看到:
Main started. Method entered. Thread starting sleep. Await 1 finished. Await 2 finished Thread stopped sleeping Method completed
我知道通过
Thread.Sleep
我正在制作停止主线程。 但据我所知,Method()不应该需要线程,因为它包含IO绑定操作。 任何人都能解释我误解的地方吗?我正在使用的AsynContext是( 这里 )。
I has spend a lot of time to understand async programming principles. But one thing is still unclear. I was confused by this code :
static async Task Method() { Console.WriteLine($"Method entered."); await Task.Delay(1000); Console.WriteLine($"Await 1 finished."); await Task.Delay(1000); Console.WriteLine($"Await 2 finished"); } static int Main(string[] args) { Console.WriteLine($"Main started."); return AsyncContext.Run(() => MainAsync(args)); } static async Task<int> MainAsync(string[] args) { var t = Method(); Console.WriteLine("Thread starting sleep."); Thread.Sleep(10000); Console.WriteLine("Thread stopped sleeping"); Console.WriteLine(t.IsCompleted ? "Method completed" : "Method not completed"); await t; return 0; }
Result :
Main started. Method entered. Thread starting sleep. Thread stopped sleeping Method not completed Await 1 finished. Await 2 finished
As I understand while Main thread is sleeping IO-bound operations from Method should be executed (cause Task.Delay emulate IO) and interrupt Main thread sequentially to continue execute Method code. So I expect to see:
Main started. Method entered. Thread starting sleep. Await 1 finished. Await 2 finished Thread stopped sleeping Method completed
I know that by
Thread.Sleep
I am making to stop Main thread. But as I understand Method() should not need thread because it consists of IO-bound operations. Can anybody explain where I am misunderstanding it?AsynContext that I am using is (here).
原文:https://stackoverflow.com/questions/43469076
最满意答案
如果你想要串行行为,这应该工作:
private void GridOnRowDataBound(object sender, GridViewRowEventArgs gridViewRowEventArgs) { if (gridViewRowEventArgs.Row.RowType != DataControlRowType.DataRow) return; var localIndex = ++_index; HttpContext.Current.Response.Write($"starting #{localIndex} <br />"); Thread.Sleep(1000); // or Task.Delay(1000).Wait(); HttpContext.Current.Response.Write($"exiting #{localIndex} <br />"); }
或尝试:
private void GridOnRowDataBound(object sender, GridViewRowEventArgs gridViewRowEventArgs) { RegisterAsyncTask(new PageAsyncTask(() => Bob(gridViewRowEventArgs))); HttpContext.Current.Response.Write($"b"); } private async Task Bob(GridViewRowEventArgs gridViewRowEventArgs) { if (gridViewRowEventArgs.Row.RowType != DataControlRowType.DataRow) return; var localIndex = ++_index; HttpContext.Current.Response.Write($"starting #{localIndex} <br />"); await Task.Delay(1000); HttpContext.Current.Response.Write($"exiting #{localIndex} <br />"); }
If you want serial behaviour, this should work:
private void GridOnRowDataBound(object sender, GridViewRowEventArgs gridViewRowEventArgs) { if (gridViewRowEventArgs.Row.RowType != DataControlRowType.DataRow) return; var localIndex = ++_index; HttpContext.Current.Response.Write($"starting #{localIndex} <br />"); Thread.Sleep(1000); // or Task.Delay(1000).Wait(); HttpContext.Current.Response.Write($"exiting #{localIndex} <br />"); }
or try:
private void GridOnRowDataBound(object sender, GridViewRowEventArgs gridViewRowEventArgs) { RegisterAsyncTask(new PageAsyncTask(() => Bob(gridViewRowEventArgs))); HttpContext.Current.Response.Write($"b"); } private async Task Bob(GridViewRowEventArgs gridViewRowEventArgs) { if (gridViewRowEventArgs.Row.RowType != DataControlRowType.DataRow) return; var localIndex = ++_index; HttpContext.Current.Response.Write($"starting #{localIndex} <br />"); await Task.Delay(1000); HttpContext.Current.Response.Write($"exiting #{localIndex} <br />"); }
相关问答
更多-
虽然没有人想帮助我,但我找到了问题的答案。 我认为id可以分享这些信息,因为它可以帮助其他人。 这是我为我的孩子gridview pageindexchanging事件想出的: protected void grdSupImages_PageIndexChanging(object sender, GridViewPageEventArgs e) { GridView gv = (GridView)sender; gv.PageIndex = e.NewPag ...
-
无论是。 当你说实例是它是动态创建并添加到页面的控件集合还是通过设计器和元素时,我真正想要确定的是什么。 如果它在代码隐藏中完成,如: GridView v = new GridView(); this.Controls.Add(v); 那么你必须每次在页面的OnLoad事件中重新创建它(或控制它的创建)以便可用。 更重要的是,它每次都必须具有完全相同的名称。 否则它将不匹配上一次的视图状态信息。 Either. What I was really trying to determine when you ...
-
在我看来,你不应该使用MVC中的任何服务器控件。 你将需要使用一个表并遍历thr所需的对象,MVC允许对HTML进行更多的控制,这样你就需要做更多的工作。 我认为你最好看看NerdDinner的例子。 http://nerddinner.codeplex.com/ 这是一个例子,