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



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

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

其中字典关键字是CCD_ 5的名称,并且值是与该对象相关联的属性的CCD_。

这是我的功能:

public Dictionary<string, List<string>> GetAllsobjectsAttributes(string accessToken, string domain, List<string> DataSourcesobjects)
{
Dictionary<string, List<string>> sobjects = new 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,
"aiPredictionField" : false,
"autoNumber" : false,
"byteLength" : 0,
"calculated" : false,
"calculatedFormula" : null,
"cascadeDelete" : false,
"caseSensitive" : false,
"compoundFieldName" : null,
"controllerName" : null,
"createable" : false,
"custom" : false,
"defaultValue" : false,
"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" : false,
"inlineHelpText" : null,
"label" : "Deleted",
"length" : 0,
"mask" : null,
"maskType" : null,
"name" : "IsDeleted",
"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" : "xsd:boolean",
"sortable" : true,
"type" : "boolean",
"unique" : false,
"updateable" : false,
"writeRequiresMasterRead" : false
},

注意:

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

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

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

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

使用Parallel.ForEach()

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

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

这只是你可能做的一个(简单的(例子。这个概念是基于这个后

我很想知道这能在多大程度上提高你的执行时间。

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字符串。Runnig这将证明,或不证明,时间是丢失的网络呼叫。我怀疑这是罪魁祸首,代码会更快。如果是这样的话,那么你需要重新思考你是如何做到的。例如,在ui中,有一个下拉列表来选择soobject,然后有另一个下拉菜单来选择字段。

最新更新