我遇到了一个优化问题,我有一个函数调用salesforce API来获取与每个salesforce-sobject
关联的属性列表,它会在1秒或1.5秒内返回列表,这还不错,并将其作为JSON返回。当我收到这个有效载荷时,问题就开始了,因为我开始将字典中接收到的每个对象属性添加为其中key
的value
,而这个函数需要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
},
注意:
- 我的字典里有1000个
sobjects
- 一开始我无法创建带范围的字段列表,因为我没有关于每个sobject返回的字段数的信息
- 每个主题的字段在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,然后有另一个下拉菜单来选择字段。