【发布时间】:2017-11-27 13:51:44
【问题描述】:
我有一个项目,我需要多个项目列表的数据。对于每个项目,我都会调用一个 api 来获取这些信息。循环工作,虽然它需要 4 到 5 分钟才能完成(这是很多)。
以前的代码是这样的:
foreach (var project in projects)
{
string url = urlOneProject + project.name + secondPartUrl + "?authtoken=" + authToken;
HttpWebRequest request;
request = (HttpWebRequest)WebRequest.Create(url);
request.Accept = "application/json";
request.ContentType = "application/json";
var executions = new Execs();
var response = (HttpWebResponse)(await request.GetResponseAsync());
using (response)
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
JavaScriptSerializer js = new JavaScriptSerializer();
var objText = reader.ReadToEnd();
executions = (Execs)js.Deserialize(objText, typeof(Execs));
}
}
execs.AddRange(executions.executions);
}
为了提高性能,我认为使用线程可能是个好主意。所以,我想出了这样的事情:
ManualResetEvent resetEvent = new ManualResetEvent(false);
int toProcess = projects.Count;
foreach (var project in projects)
{
new Thread(() =>
{
string url = urlOneProject + project.name + secondPartUrl + "?authtoken=" + authToken;
HttpWebRequest request;
request = (HttpWebRequest)WebRequest.Create(url);
request.Accept = "application/json";
request.ContentType = "application/json";
var executions = new Execs();
var response = (HttpWebResponse)(await request.GetResponseAsync());
using (response)
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
JavaScriptSerializer js = new JavaScriptSerializer();
var objText = reader.ReadToEnd();
executions = (Execs)js.Deserialize(objText, typeof(Execs));
}
}
lock (execs)
{
execs.AddRange(executions.executions);
}
if (Interlocked.Decrement(ref toProcess) == 0)
resetEvent.Set();
}).Start();
}
这段代码的问题在于:
var response = (HttpWebResponse)(await request.GetResponseAsync());
从我添加Thread 的那一刻起就不再编译了。我得到的错误是
"'await' 运算符只能在异步 lambda 表达式中使用"
当我不使用线程时,这不是问题。 GetResponseAsync 是一个async 函数,必须使用await。我尝试删除它(我同意这不合逻辑,但我用完了选项)但编译器告诉我我需要一个 await 来获得 async 函数。
我不太明白Thread 的实现有什么变化。
我没有正确机械地使用螺纹吗?我应该怎么做才能纠正这个问题或实现我想要正确做的事情?
【问题讨论】:
-
要修复编译器错误,您需要将异步 lambda 传递给线程构造函数:
new Thread(async () => ... -
与显式启动线程相比,您将从 async / await 和 Task.WhenAll 中获得更多收益。 (并且优先考虑任务而不是线程 - 不太可能在脚上开枪)。
-
如果你想使用
Task而不是Thread来分割Task和project,只需使用projects.Select(async project => ... -
线程太贵了,你也不希望任何时候有太多的线程/套接字。
-
而@StuartLC 提供了一个很好的答案。如果您打算继续沿
async路径前进,那么值得研究一下 HttpClient,它有大量直接的async支持。
标签: c# .net multithreading asynchronous async-await