微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何优化迭代多个列表并稍后将它们添加到 C# 中的字典的函数的执行时间?

如何解决如何优化迭代多个列表并稍后将它们添加到 C# 中的字典的函数的执行时间?

我有一个优化问题,我有一个函数可以调用 salesforce API 来获取与每个 salesforce sobject 关联的属性列表,它会在 1 秒或 1.5 秒内返回列表,这还不错,然后返回它作为 JSON。当我收到此有效负载时,问题就开始了,因为我开始将字典中收到的每个对象属性添加为其中的 valuekey 并且此函数需要 8 到 12 分钟,这并不擅长都是因为在那之后我应该循环所有字典及其值以在视图中呈现它们(浪费更多时间)。

所以我的字典看起来像这样 Dictionary<string,List<string>> sobjects = new Dictionary<string,List<string>>();

其中字典键是 sobject名称,值是与该对象关联的属性list<string>

这是我的功能

public Dictionary<string,List<string>> GetAllsobjectsAttributes(string accesstoken,string domain,List<string> DataSourcesobjects)
        {
            Dictionary<string,List<string>>();
            using (HttpClient client = new HttpClient())
            {
                try
                {


                    client.BaseAddress = new Uri(URL);
                    client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer",accesstoken);
                    
                    foreach (var sobject in DataSourcesobjects)
                    {
                        List<string> fields = new List<string>();
                        sobjects.Add(sobject,fields);
                        var fieldsResult = client.GetAsync("/services/data/v51.0/sobjects/"+sobject+"/describe").Result;
                        string fieldData = fieldsResult.Content.ReadAsstringAsync().Result;
                        dynamic fieldsDataObject = JsonConvert.DeserializeObject<dynamic>(fieldData);
                        JArray fieldslist = fieldsDataObject.fields;
                        foreach (JToken item in fieldslist)
                        {
                            fields.Add(item["name"].ToString());
                        }
                        
                    }
                    return sobjects;
                }
                catch (Exception e)
                {
                    throw e;
                }
            }
            
        }

这是我的视图代码

@foreach (keyvaluePair<string,List<string>> sobject in Model.DataSourceAttributes)
            {
                <optgroup label="@sobject.Key">
                    
                        @foreach (var field in sobject.Value)
                        {
                        <option value="datasourceattribute">@field </option>
                        }
                </optgroup>
            }

这里是从 API 返回的 JSON 的一部分。 (由于太长,无法全部发布,但您可以从其中的一部分看到它的外观)。

"fields" : [ {
    "aggregatable" : true,"aiPredictionField" : false,"autoNumber" : false,"byteLength" : 18,"calculated" : false,"calculatedFormula" : null,"cascadeDelete" : false,"caseSensitive" : false,"compoundFieldName" : null,"controllerName" : null,"createable" : false,"custom" : false,"defaultValue" : null,"defaultValueFormula" : null,"defaultedOnCreate" : true,"dependentPicklist" : false,"deprecatedAndHidden" : false,"digits" : 0,"displayLocationInDecimal" : false,"encrypted" : false,"externalId" : false,"extraTypeInfo" : null,"filterable" : true,"filteredLookupInfo" : null,"formulaTreatNullNumberAsZero" : false,"groupable" : true,"highScaleNumber" : false,"htmlFormatted" : false,"idLookup" : true,"inlineHelpText" : null,"label" : "Account ID","length" : 18,"mask" : null,"maskType" : null,"name" : "Id","nameField" : false,"namePointing" : false,"nillable" : false,"permissionable" : false,"picklistValues" : [ ],"polymorphicForeignKey" : false,"precision" : 0,"queryBydistance" : false,"referenceTargetField" : null,"referenceto" : [ ],"relationshipName" : null,"relationshipOrder" : null,"restrictedDelete" : false,"restrictedPicklist" : false,"scale" : 0,"searchPrefilterable" : false,"soapType" : "tns:ID","sortable" : true,"type" : "id","unique" : false,"updateable" : false,"writeRequiresMasterRead" : false
  },{
    "aggregatable" : false,"byteLength" : 0,"defaultValue" : false,"idLookup" : false,"label" : "Deleted","length" : 0,"name" : "IsDeleted","soapType" : "xsd:boolean","type" : "boolean",

注意:

  1. 我的字典中有 1000 个 sobjects
  2. 一开始我无法创建具有范围的字段列表,因为我没有关于为每个 sobject 返回的字段计数的信息。
  3. 每个 sobject 的字段在 7 到 20 之间,并且可能因组织而异。

我试图让它变得更好的事情:

将列表作为 ref 传递给函数,而不是复制所有 1000 个 sobjects 列表,但我听说它没有任何附加值,因为每次添加值时都会对其进行查找操作。

我仍在尝试和测试的东西:

使用Parallel.ForEach()

解决方法

“如何优化 [您的] 函数的执行时间...”——我相信这是您主要关心的问题。

IMO - 列表和字典的优化不会给你带来实质性的速度提升......正如其他人所说:你的主要瓶颈是 api 调用——制作 1000 个。您可能希望同时运行尽可能多的程序,但要避免端口耗尽。然后使用这个建议的实现 - 您将希望使用 ConcurrentDictionary。

这只是您可能执行的操作的(简单)示例。该概念基于 this post

我很想知道这在多大程度上改善了您的执行时间。

        public ConcurrentDictionary<string,List<string>> GetAllsobjectsAttributes(string accessToken,string domain,List<string> DataSourcesobjects)
        {
            int maxRequests = 10;
            // just one way to try to keep to maxRequests # of api calls at a time
            SemaphoreSlim semaphore = new SemaphoreSlim(maxRequests);

            ConcurrentDictionary<string,List<string>> sobjects = new ConcurrentDictionary<string,List<string>>();

            using (HttpClient client = new HttpClient())
            {
                try
                {
                    client.BaseAddress = new Uri(URL);
                    client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer",accessToken);

                    List<Task> tasks = new List<Task>();
                    foreach (var sobject in DataSourcesobjects)
                    {
                        tasks.Add(Task.Run(async () =>
                        {
                            try
                            {
                                await semaphore.WaitAsync();

                                List<string> fields = new List<string>();
                                sobjects[sobject] = fields;
                                var fieldsResult = await client.GetAsync("/services/data/v51.0/sobjects/" + sobject + "/describe");
                                string fieldData = await fieldsResult.Content.ReadAsStringAsync();
                                dynamic fieldsDataObject = JsonConvert.DeserializeObject<dynamic>(fieldData);
                                JArray fieldslist = fieldsDataObject.fields;
                                foreach (JToken item in fieldslist)
                                {
                                    fields.Add(item["name"].ToString());
                                }
                            }
                            catch (Exception ex) when (ex is OperationCanceledException || ex is TaskCanceledException)
                            {
                                // More error handling?
                                Console.WriteLine($"Failed for sobject: {sobject}");
                            }
                            finally
                            {
                                semaphore.Release();
                            }
                            return Task.CompletedTask;
                        }));
                    }
                    Task.WaitAll(tasks.ToArray());

                    return sobjects;
                }
                catch (Exception e)
                {
                    throw e;
                }
            }
        }
,

注释掉设置 var fieldResults 的行并将 fieldData 硬编码为大 json 字符串。运行这将证明或不证明网络调用中的时间丢失了。我怀疑这是罪魁祸首,代码会快很多。如果是这种情况,那么你需要重新考虑你是如何做的。例如,在 ui 中有一个下拉列表来选择 sobject,然后另一个下拉列表选择字段。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。