我认为Console.WriteLine命令(lengthTask.Result);阻止UI线程。我使它工作的唯一方法是将其更改为:lengthTask.ContinueWith(t => Console.WriteLine(t.Result),TaskContinuationOptions.ExecuteSynchronously);它是否正确?
是的,这是正确的。 Console.WriteLine(lengthTask.Result)
将阻止您的UI线程,但它在控制台应用程序中可以正常工作,因为控制台应用程序使用线程池sycnrhonization上下文,其中包含多个线程。
你ContinueWith
通过将工作的解决方案,这是后话,你还可以做异步的await,基本上自动调度方法作为延续的休息:
static async Task PrintPageLength()
{
Task<int> lengthTask =
GetPageLengthAsync("http://csharpindepth.com");
Console.WriteLine(await lengthTask.ConfigureAwait(false));
}
的ConfigureAwait(false)
用于在异步工作完成后避免上下文切换,类似于您使用TaskContinuationOptions.ExecuteSynchronously
与ContinueWith
。
在返回类型为Task时,第一种方法的返回长度是如何工作的?
异步等待代码不是你所看到的是你得到的。它编译成一个状态机。如果你拆开你的代码,它看起来更像是这样的:
[AsyncStateMachine(typeof(<GetPageLengthAsync>d__0)), DebuggerStepThrough]
private static Task<int> GetPageLengthAsync(string url)
{
<GetPageLengthAsync>d__0 d__;
d__.url = url;
d__.<>t__builder = AsyncTaskMethodBuilder<int>.Create();
d__.<>1__state = -1;
d__.<>t__builder.Start<<GetPageLengthAsync>d__0>(ref d__);
return d__.<>t__builder.Task;
}
状态机看起来是这样的:
[CompilerGenerated]
private struct <GetPageLengthAsync>d__0 : IAsyncStateMachine
{
public int <>1__state;
public AsyncTaskMethodBuilder<int> <>t__builder;
private object <>t__stack;
private TaskAwaiter<string> <>u__$awaiter4;
public HttpClient <client>5__1;
public Task<string> <fetchTextTask>5__2;
public int <length>5__3;
public string url;
private void MoveNext()
{
int num;
try
{
bool flag = true;
switch (this.<>1__state)
{
case -3:
goto Label_0113;
case 0:
break;
default:
this.<client>5__1 = new HttpClient();
break;
}
try
{
TaskAwaiter<string> awaiter;
if (this.<>1__state != 0)
{
this.<fetchTextTask>5__2 = this.<client>5__1.GetStringAsync(this.url);
awaiter = this.<fetchTextTask>5__2.GetAwaiter();
if (!awaiter.IsCompleted)
{
this.<>1__state = 0;
this.<>u__$awaiter4 = awaiter;
this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter<string>, Form1.<GetPageLengthAsync>d__0>(ref awaiter, ref this);
flag = false;
return;
}
}
else
{
awaiter = this.<>u__$awaiter4;
this.<>u__$awaiter4 = new TaskAwaiter<string>();
this.<>1__state = -1;
}
string result = awaiter.GetResult();
awaiter = new TaskAwaiter<string>();
int length = result.Length;
this.<length>5__3 = length;
num = this.<length>5__3;
}
finally
{
if (flag && (this.<client>5__1 != null))
{
this.<client>5__1.Dispose();
}
}
}
catch (Exception exception)
{
this.<>1__state = -2;
this.<>t__builder.SetException(exception);
return;
}
Label_0113:
this.<>1__state = -2;
this.<>t__builder.SetResult(num);
}
[DebuggerHidden]
private void SetStateMachine(IAsyncStateMachine param0)
{
this.<>t__builder.SetStateMachine(param0);
}
}
感谢您提供丰富的答案。不过,我测试过'.ConfigureAwait(false); +在WinForms上等待lengthTask'并崩溃。它适用于'ConfigureAwait(true)' – 2015-02-11 07:43:07
对不起,应该是'Console.WriteLine(await lengthTask.ConfigureAwait(false));',否则会出现编译器错误。我今天早上测试了它,它工作。 – 2015-02-11 22:58:22