我正在使用C#和ASP.NET Core6MVC。
我需要使用偏移量从API中获取所有结果,无论是64条记录还是6300条记录。调整偏移量,执行并发调用或并行调用,以一次获得所有记录。我需要用最好的方法。
我正在调用一个API,它会在每次调用中产生100条最大记录。虽然总的结果(totalResult)可以是65,120,1500或2520,或6534等。有一个偏移整数,我可以传递到API,以得到进一步的100个结果每次。默认情况下,它是零,这可以带来100个最大记录。
例如,对于65的totalResult,偏移量0就足够了,因为它将带来所有65条记录。对于150的totalResult,偏移量0将带来100条记录,然后在下一次迭代中,偏移量必须为100才能带来更多记录。同样地,对于6530最大记录,偏移必须调整100,200,300.得到所有的结果。
现在,我需要并行运行这个任务,以避免延迟时间。
这是我的职责:
var offset = 0
// My async call method
var addressResult = await _postcode.GetAddresses(strPostcode, offset);
if (addressResult?.Results != null && addressResult.Results.Any())
{
// concurrency code to run here with offset
int total = addressResult.Header.TotalResults; //Total Result e,g 6500
var thePostcoderesult = addressResult.Results;
// max result could be any number depends on the Total Result if it is
int maxresult = thePostcoderesult.Count();
}因此,当对API的所有并发调用结束时,thePostcoderesult应该将所有结果都添加到其中。
var thePostcoderesult = addressResult.Results;现在,我知道我们可以通过
await Parallel.ForEachAsync(offsets, options, async (offset, ct) =>在帖子的帮助下,勾选答案How to make multiple API calls faster?
我试着实现这个逻辑--但它只给了我1000个结果,因为它与偏移量有关,并行循环不对齐。因为任务只运行了10次,结果只有1000个--尽管我正在搜索的邮政编码是1630。
这里是我更新的代码,但正如我提到的,它不会等待完成或运行,直到偏移的总数。
var offset = 0
var addressResult = await _postcode.GetAddresses(strPostcode, offset);
if (addressResult?.Results != null && addressResult.Results.Any())
{
int total = addressResult.Header.TotalResults;
// Setting offset here - but something is not right
IEnumerable<int> offsets = Enumerable
.Range(0, total)
.Select(n => checked(n * 100))
.TakeWhile(offset => offset < Volatile.Read(ref total));
// wanted to use 10 parallel threads which is a safe bet I believe
var options = new ParallelOptions() { MaxDegreeOfParallelism = 10 };
var thePostcoderesult = new List<AddressResult>();
await Parallel.ForEachAsync(offsets, options, async (offset, ct) =>
{
var addressResult = await _postcode.GetAddresses(strPostcode, offset);
if (offset == 0)
{ //I am not using it
//Volatile.Write(ref total, Jresult.Results.Count());
}
thePostcoderesult.AddRange(addressResult.Results);
});
return thePostcoderesult;
}为详细的帖子事先表示歉意-如果您能帮助做这个更正确或整洁的方式,欢迎您。
非常感谢
发布于 2022-11-29 03:59:29
你有很多事情要做,我觉得没必要那么复杂。由于最初的GetAddresses调用似乎告诉您将拥有多少记录,所以您可以这样做:
var initialResponse = await _postcode.GetAddresses(strPostcode, 0);
if (initialResponse?.Results == null || !initialResponse.Results.Any())
{
return;
}
var totalPostCodeResults = new AddressResult[initialResponse.Header.TotalResults];
// fill up to the first 100 since you have it and bail if that's all there is
FillItems(initialResponse.Results, totalPostCodeResults, 0);
if(totalPostCodeResults.Length <= 100)
return totalPostCodeResults;
// Fill the offsets (aka start indexes) starting at 100
var offsets = new List<int>();
var offset = 100;
while(offset < totalPostCodeResults.Length)
{
offsets.Add(offset);
offset+=100;
}
// TODO: add the last one using modulus
// Kick off a task for each offset range
var tasks = new Task[offsets.Count()];
for(int i = 0; i < tasks.Length; i++)
{
// copy i to scoped variable to avoid parallel messiness
var index = i;
tasks[index] = Task.Run(async () => {
var response = await _postcode.GetAddresses(strPostcode, offsets[index]);
FillItems(response.Results, totalPostCodeResults, offsets[index]);
}
}
// Wait for all of them to finish
Task.WaitAll(tasks);
return totalPostCodeResults
void FillItems(List<AddressResult> results, AddressResult[] totalArray, int startIndex)
{
var index = startIndex;
results.ForEach(item => totalArray[index++] = item);
}https://stackoverflow.com/questions/74608696
复制相似问题