C# Task.whalll多线程按顺序而不是并行运行
我有一个应用程序,我最初在其中建立,在我所属的所有团队中,我拥有多少(Microsoft)团队。C# Task.whalll多线程按顺序而不是并行运行,c#,asp.net,asynchronous,multitasking,C#,Asp.net,Asynchronous,Multitasking,我有一个应用程序,我最初在其中建立,在我所属的所有团队中,我拥有多少(Microsoft)团队。 因此,如果我是37支球队的成员,我需要列出我实际拥有的13支球队的名单 它可以工作-查询每个团队所有者的MS图-但是一些用户是数百个团队的所有者,很明显,当必须等待顺序加载时,加载时间是不可接受的。 因此,我正试图用任务解决这个问题。选择和任务。当所有完成时。但是,任务按顺序运行,而不是并行运行。 我很有兴趣将总加载时间降低到大约250毫秒,而不是250乘以37。 我已经读到,如果我在任务中使用.R
因此,如果我是37支球队的成员,我需要列出我实际拥有的13支球队的名单 它可以工作-查询每个团队所有者的MS图-但是一些用户是数百个团队的所有者,很明显,当必须等待顺序加载时,加载时间是不可接受的。 因此,我正试图用
任务解决这个问题。选择和任务。当所有完成时。但是,任务按顺序运行,而不是并行运行。
我很有兴趣将总加载时间降低到大约250毫秒,而不是250乘以37。
我已经读到,如果我在任务中使用.Result
,导致它按顺序运行,那么任务.whalll
会被冒犯,但我不知道如何使它在并行线程中运行
private static async Task DispatchGetTeamOwnersAsync(JEnumerable<JToken> userTeams, GraphittiBox.Model.TokenObject token)
{
var tasks = userTeams.Select(async team =>
{
Team t = JsonConvert.DeserializeObject<Team>(team.ToString());
Stopwatch clock = Stopwatch.StartNew();
LogService.WriteLog("await: GetOwnersOfTeamAsync");
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(token.Token_type, token.Access_token);
var url = new Uri("https://graph.microsoft.com/v1.0/groups/{groupId}/owners?$select=mail,id,displayName".Replace("{groupId}", t.Id));
var response = httpClient.GetAsync(url);
var content = response.Result.Content.ReadAsStringAsync();
JObject owners = JsonConvert.DeserializeObject<JObject>(content.Result);
JsonOwnersCollection.Add(new OwnersAsyncList(t.Id, owners));
clock.Stop();
LogService.WriteLog("Done (" + clock.ElapsedMilliseconds.ToString() + " ms)");
});
await Task.WhenAll(tasks);
}
您正在使用
var content = response.Result.Content.ReadAsStringAsync();
.Result
部分将导致阻塞,直到任务完成。你应该等待任务。这里使用var
隐藏了这样一个事实,即你的中间产物是task
,而不是T
。应避免使用。结果,因为它会阻塞
//var response = httpClient.GetAsync(url);
//var content = response.Result.Content.ReadAsStringAsync();
//JObject owners = JsonConvert.DeserializeObject<JObject>(content.Result);
var response = await httpClient.GetAsync(url);
var content = await response.Content.ReadAsStringAsync();
JObject owners = JsonConvert.DeserializeObject<JObject>(content);
//var response=httpClient.GetAsync(url);
//var content=response.Result.content.ReadAsStringAsync();
//JObject owners=JsonConvert.DeserializeObject(content.Result);
var response=wait-httpClient.GetAsync(url);
var content=await response.content.ReadAsStringAsync();
JObject owners=JsonConvert.DeserializeObject(内容);
请注意,您的原始循环代码没有任何wait
s,这就是为什么您的任务是同步的,并且所有任务都是按顺序运行的。所有这些都可以简化为:
var ownerTasks=userTeams
.Cast<JObject>()
.Select(j=>{
var id=j.GetValue("Id");
return $"https://graph.microsoft.com/v1.0/groups/{id}/owners?$select=mail,id,displayName";
})
.Select(async url=>await httpClient.GetStringAsync(url));
.Select(json=>JObject.Parse(json));
var owners=await Task.WhenAll(ownerTasks);
还有其他可以改变的事情。这两条线:
var response = await httpClient.GetAsync(url);
var content = await response.Content.ReadAsStringAsync();
可以替换为
var content=await httpClient.GetStringAsync(url);
URL可以一步构造,避免临时字符串:
var url = new Uri($"https://graph.microsoft.com/v1.0/groups/{t.Id}/owners?$select=mail,id,displayName");
与其将团队
转换为字符串
,只将其反序列化为团队
,不如传递团队
对象列表?即使有理由使用JSToken
也没有理由序列化和解析它。JObject
是一个JToken
。如果改为传递JArray
或JProperty
,序列化/反序列化将失败
获取ID可以通过以下方式完成:
var id=((JObject)team).GetValue("Id");
所有这些都变成:
var ownerTasks=userTeams
.Cast<JObject>()
.Select(j=>{
var id=j.GetValue("Id");
return $"https://graph.microsoft.com/v1.0/groups/{id}/owners?$select=mail,id,displayName";
})
.Select(async url=>await httpClient.GetStringAsync(url));
.Select(json=>JObject.Parse(json));
var owners=await Task.WhenAll(ownerTasks);
任务。当所有
等待已经执行的任务时,它不会运行它们。代码有几个bug-创建一个新的HttpClient
实例而不是重用一个实例是一个严重的bug。您没有注意到这一点,因为下一个bug使用.Result
阻止异步调用,确保一次只能执行一个GetAsync()
或ReadAsStringAsync
调用。你有一个同步循环。它编译的唯一原因是(否则没有用)async
keyword@DmitryStepanov谢谢,fixed看起来应该这样做:.Select(asyncjson=>JObject.Parse(awaitjson))代码>作为json
仍然是任务
而不是字符串
var id=((JObject)team).GetValue("Id");
var ownerTasks=userTeams
.Cast<JObject>()
.Select(j=>{
var id=j.GetValue("Id");
return $"https://graph.microsoft.com/v1.0/groups/{id}/owners?$select=mail,id,displayName";
})
.Select(async url=>await httpClient.GetStringAsync(url));
.Select(json=>JObject.Parse(json));
var owners=await Task.WhenAll(ownerTasks);
var dop=new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism=8 //Adjust based on Graph's throttling limits
};
var block=new TransformBlock<string,JObject>(async j=>{
var id=j.GetValue("Id");
var url= $"https://graph.microsoft.com/v1.0/groups/{id}/owners?$select=mail,id,displayName";
var json=await httpClient.GetStringAsync(url));
return JObject.Parse(json)
})
var buffer=new BufferBlock<JObject>();
block.LinkTo(buffer)
foreach(var j in teams)
{
block.Post(j);
}
block.Complete();
//Wait for all operations to complete
await block.Completion;
//The buffer contains all results now