我发现以下代码实际上不会等待任务client.SendAsync(),如果我使用实现的话:
taskList.Add(Task.Factory.StartNew(() => new Program().Foo()));
如果我将其从更改Task.Factory.StartNew()
为正义new Program().Foo()
或Task.Run(() => new Program.Foo()
它将正确输出一些信息。两者之间有什么区别?
internal class Program
{
private async Task Foo()
{
while (true)
{
var client = new HttpClient();
var requestMessage = new HttpRequestMessage(HttpMethod.Head, "http://www.google.com");
HttpResponseMessage response = await client.SendAsync(requestMessage);
Console.WriteLine(response.RequestMessage.RequestUri.ToString());
}
}
private static void Main(string[] args)
{
var taskList = new List<Task>();
// This won't output anything.
taskList.Add(Task.Factory.StartNew(() => new Program().Foo()));
// This will.
taskList.Add(Task.Run(() => new Program().Foo()));
// So does this.
taskList.Add(new Program().Foo());
Task.WaitAll(taskList.ToArray());
}
}
根据此MSDN文章,似乎Task.Run(someAction);
相当于Task.Factory.StartNew(someAction, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
但是,即使我将代码更改为此,也不会输出任何内容。为什么?
internal class Program
{
private async Task Foo()
{
while (true)
{
var client = new HttpClient();
var requestMessage = new HttpRequestMessage(HttpMethod.Head, "http://www.google.com");
HttpResponseMessage response = await client.SendAsync(requestMessage);
Console.WriteLine(response.RequestMessage.RequestUri.ToString());
}
}
private static void Main(string[] args)
{
var taskList = new List<Task>();
taskList.Add(Task.Factory.StartNew(() => new Program().Foo(), CancellationToken.None,
TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
//taskList.Add(Task.Run(() => new Program().Foo()));
//taskList.Add(new Program().Foo());
Task.WaitAll(taskList.ToArray());
}
}
问题出在Task.Factory.StartNew
不是“任务感知”的事实。意思是,方法调用的返回类型StartNew
实际上是Task<Task>
。这意味着您仅在等待外部任务完成,而不是内部任务。
一个简单的解决方案是使用TaskExtensions.Unwrap()
方法:
private static void Main(string[] args)
{
var taskList = new List<Task>();
taskList.Add(Task.Factory.StartNew(() => new Program().Foo()).Unwrap());
Task.WaitAll(taskList.ToArray());
}
Task.Run
确实有效,因为它是“任务感知”的。它有一个重载,接受一个Func<Task>
内部调用Unwrap
,仅返回内部任务。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句