[英]Threads with async Task functions C#/.NET / await not compiling
I have a project where I need multiple data for a list of projects. 我有一个项目,我需要多个数据才能获得项目列表。 For each project I call an api to get me this information.
对于每个项目,我都调用一个api来获取此信息。 The loop works, although it takes 4 to 5 minutes to finish(Which is A LOT).
尽管需要4到5分钟才能完成循环(虽然很多),但循环仍然有效。
The code used to look like this : 以前的代码看起来像这样:
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);
}
To improve performance I thought that using threads might be a good idea. 为了提高性能,我认为使用线程可能是一个好主意。 So, I came up with something like this:
所以,我想到了这样的东西:
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();
}
The problem with this code is that the line: 此代码的问题是该行:
var response = (HttpWebResponse)(await request.GetResponseAsync());
doesn't compile anymore from the moment I added Thread
. 从我添加
Thread
的那一刻起,它就不再编译了。 And the error I get is 我得到的错误是
"The 'await' operator can only be used within an async lambda expression "
“'await'运算符只能在异步lambda表达式中使用”
That wasn't a problem when I didn't use threads. 当我不使用线程时,这不是问题。 The
GetResponseAsync
is an async
function and the use of the await
is compulsory. GetResponseAsync
是async
函数,必须使用await
。 I tried deleting it (which wasn't logical I agree but I ran out of options) but the compiler tells me I need an await
for an async
function. 我尝试删除它(我同意这是不合逻辑的,但是我用尽了所有选项),但是编译器告诉我我需要
await
async
功能。 I don't quite understand what changes with the implementation of the Thread
. 我不太了解
Thread
的实现会发生什么变化。
Didn't I use the threads mechanically correctly? 我没有正确地机械地使用螺纹吗? What should I do to correct this or to implement what I want to do correctly?
我该怎么做才能纠正此问题或正确执行我想做的事情?
You are mixing multiple paradigms of coding, viz async / await
, and oldschool Thread starting and synchronization, which is likely to lead to trouble. 您正在混合使用多种编码范例,即
async / await
和oldschool线程启动和同步,这可能会导致麻烦。
As per the above comments 根据以上评论
await
in otherwise synchronous code passed to the thread. await
。 You can qualify lambdas as async
as well. async
。 Task
is a much safer paradigm than Thread
, and TPL provides rich and expressive tools to assist in asynchrony and parallelism. Task
是比Thread
更安全的范例,而TPL提供了丰富而富有表现力的工具来辅助异步和并行性。 var myTasks = projects.Select(async project =>
{
var url = $"urlOneProject{project.name}{secondPartUrl}?authtoken={authToken}";
var request = (HttpWebRequest) WebRequest.Create(url);
request.Accept = "application/json";
request.ContentType = "application/json";
using (var response = (HttpWebResponse) (await request.GetResponseAsync()))
using (var reader = new StreamReader(response.GetResponseStream()))
{
var objText = await reader.ReadToEndAsync();
return JsonConvert.DeserializeObject<Execs>(objText);
}
});
var execs = (await Task.WhenAll(myTasks))
.SelectMany(result => result.executions);
Other notes 其他注意事项
JavaScriptSerializer
- even the MSDN docco says to use NewtonSoft Json JavaScriptSerializer
甚至MSDN docco都说要使用NewtonSoft Json reader.ReadToEndAsync
which I've included. reader.ReadToEndAsync
的异步版本。 ManualResetEvent
- since each Task returns it's result, we'll leave it to Task.WhenAll
to collate the data. ManualResetEvent
因为每个Task都会返回它的结果,所以我们将其留给Task.WhenAll
来整理数据。 executions
with a SelectMany
SelectMany
来平化多个executions
的子级 using
clauses are stackable - it saves a bit of eyestrain on the indentation. using
子句是可堆叠的-节省了缩进的视线。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.