我创建了一个 asp.net webapi 测试应用程序,这是我的测试代码:
当我使用 result = index.ToString() + this.getresult().Result;
时,响应时间为 2 秒。如果我使用 Thread.Sleep(100); result = index.ToString();
,只需要200ms。
public class HomeController : Controller
{
public string Test()
{
var listName = new List<int>();
for (int i = 0; i < 100; i++)
{
listName.Add(i);
}
var response = Task.WhenAll(listName.Select(sendrequest)).Result;
return string.Join(",", response);
}
public async Task<string> sendrequest(int index)
{
return await Task.Factory.StartNew(() =>
{
string result = string.Empty;
try
{
Thread.Sleep(100); result = index.ToString();
//result = index.ToString() + this.getresult().Result;
}
catch (Exception ex)
{
System.IO.File.AppendAllText("D:\\WebService\\FelixTest\\log.txt",ex.ToString());
}
return result;
}).ConfigureAwait(false);
}
public async Task<string> getresult()
{
await Task.Delay(100);
return "OK";
}
}
最佳答案
我认为您正在遭受 ThreadPool
线程饥饿的困扰。问题出在你注释掉的那一行
//result = index.ToString() + this.getresult().Result;
通过访问 Task.Result
属性,您将在 getresult()< 返回的
方法。 Wait操作会阻塞当前线程执行,这意味着下一个Task必须安排在另一个线程上等等。当您启动 100 个任务时,所有这些任务都会阻塞,ThreadPool 将尝试启动新的托管线程来满足需求,这是一个耗时的过程。Task
上引起 Wait
/
我会重新组织您的代码,以便除了一个顶级 Test
方法之外的所有内容都是异步的。在这个例子中,我不确定为什么你需要 Task.Factory.StartNew()
因为任务已经(至少部分地)并行运行,因为它们使用异步等待图案。也许您的真实示例需要在后台线程上安排任务?如果您不需要使用 Factory.StartNew()
,我建议您像这样重写 sendrequest
:-
public async Task<string> sendrequest(int index)
{
string result = string.Empty;
try
{
result = index.ToString() + await this.getresult();
}
catch (Exception ex)
{
System.IO.File.AppendAllText("D:\\WebService\\FelixTest\\log.txt",ex.ToString());
}
return result;
}
如果你确实需要使用 Factory.StartNew()
你仍然可以实现同样的事情,但是你传递给 StartNew
的委托(delegate)应该被标记为 async
。
关于c# - 为什么这么慢,.net任务嵌套子任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40418647/