我正在构建一个解决方案,以从 for 循环内的 API 调用中找到所需的值。
我基本上需要将 for 循环的索引传递给 API,其中一个索引将返回所需的输出,在那一刻我希望 for 循环中断,但我需要提高这个过程的效率。我想在没有 await
的情况下使其异步,以便当某些 API 返回所需的输出时,它会中断循环。
每个 API 调用大约需要 10 秒,所以如果我使用异步或多线程,我会大大减少执行时间。
我没有找到关于如何制作异步/不等待 HTTP 请求的任何好的方向。
有什么建议吗?
for (int i = 0; i < 60000; i += 256)
{
Console.WriteLine("Incrementing_value: " + i);
string response = await client.GetStringAsync(
"http://localhost:7075/api/Function1?index=" + i.ToString());
Console.WriteLine(response);
if (response != "null")//
{
//found the desired output
break;
}
}
答案 0 :(得分:1)
您可以并行运行请求,并在找到所需输出后取消它们:
public class Program {
public static async Task Main() {
var cts = new CancellationTokenSource();
var client = new HttpClient();
var tasks = new List<Task>();
// This is the number of requests that you want to run in parallel.
const int batchSize = 10;
int requestId = 0;
int batchRequestCount = 0;
while (requestId < 60000) {
if (batchRequestCount == batchSize) {
// Batch size reached, wait for current requests to finish.
await Task.WhenAll(tasks);
tasks.Clear();
batchRequestCount = 0;
}
tasks.Add(MakeRequestAsync(client, requestId, cts));
requestId += 256;
batchRequestCount++;
}
if (tasks.Count > 0) {
// Await any remaining tasks
await Task.WhenAll(tasks);
}
}
private static async Task MakeRequestAsync(HttpClient client, int index, CancellationTokenSource cts) {
if (cts.IsCancellationRequested) {
// The desired output was already found, no need for any more requests.
return;
}
string response;
try {
response = await client.GetStringAsync(
"http://localhost:7075/api/Function1?index=" + index.ToString(), cts.Token);
}
catch (TaskCanceledException) {
// Operation was cancelled.
return;
}
if (response != "null") {
// Cancel all current connections
cts.Cancel();
// Do something with the output ...
}
}
}
请注意,此解决方案使用一种简单的机制来限制并发请求的数量,更高级的解决方案将使用信号量(如某些评论中所述)。
答案 1 :(得分:1)
有多种方法可以解决此问题。我个人最喜欢使用 ActionBlock<T>
库中的 TPL Dataflow 作为处理引擎。此组件为接收到的每个数据元素调用提供的 public $role;
public $permissions;
public $selectedPermissions = [];
protected $listeners = ['eidtRole'];
public function mount()
{
$this->permissions = Permission::get();
}
public function eidtRole(Role $role)
{
$this->role = $role;
$this->selectedPermissions = $this->rolePermissions = $role->permissions()->pluck('id')->map(function ($id) {
return strval($id);
})->toArray();
}
委托,也可以提供异步委托 (Action<T>
)。它有许多有用的功能,包括(除其他外)可配置的并行度/并发度,以及通过 Func<T, Task>
取消。下面是一个利用这些功能的实现:
CancellationToken
TPL 数据流库内置于 .NET Core / .NET 5。它可以作为 .NET Framework 的包使用。
即将推出的 .NET 6 将采用新的 API Parallel.ForEachAsync
,它也可用于以类似方式解决此问题。