Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Task.whalll多线程按顺序而不是并行运行_C#_Asp.net_Asynchronous_Multitasking - Fatal编程技术网

C# Task.whalll多线程按顺序而不是并行运行

C# Task.whalll多线程按顺序而不是并行运行,c#,asp.net,asynchronous,multitasking,C#,Asp.net,Asynchronous,Multitasking,我有一个应用程序,我最初在其中建立,在我所属的所有团队中,我拥有多少(Microsoft)团队。 因此,如果我是37支球队的成员,我需要列出我实际拥有的13支球队的名单 它可以工作-查询每个团队所有者的MS图-但是一些用户是数百个团队的所有者,很明显,当必须等待顺序加载时,加载时间是不可接受的。 因此,我正试图用任务解决这个问题。选择和任务。当所有完成时。但是,任务按顺序运行,而不是并行运行。 我很有兴趣将总加载时间降低到大约250毫秒,而不是250乘以37。 我已经读到,如果我在任务中使用.R

我有一个应用程序,我最初在其中建立,在我所属的所有团队中,我拥有多少(Microsoft)团队。
因此,如果我是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