我有一个异步C#方法,在这里我获取HTTP资源,并且在无限循环中执行它。但是,我不想太快地使用资源。我当前的代码是:
Import-Csv
但是,我希望能够确保我发出HTTP请求的频率不会超过每10秒一次。因此,我想在循环开始时启动一个10秒计时器,最后说“等待10秒计时器完成”。在C#.NET中有没有办法做到这一点?
答案 0 :(得分:13)
最简单的方法:
while (true) {
var rateLimit = Task.Delay(TimeSpan.FromSeconds(10));
// ...await your http/whatever
await rateLimit;
}
如果http工作超过10秒钟,await rateLimit
将立即完成。
但是,您可以选择比较http工作之前和之后的时间,以查看是否甚至需要等待。更像是:
while (true) {
var timeBefore = ...
// ...await your http/whatever
var timeAfter = ...
// ... calculate time left
if (timeLeft > TimeSpan.Zero) await Task.Delay(timeLeft);
}
这避免了Task.Delay
在立即完成的情况下所需的负担。
答案 1 :(得分:5)
在开始循环时创建一个StopWatch
(并启动它)。
然后,当GetAsync
方法返回时,您将读取ElapsedMilliseconds。从10000减去该值。现在执行:
await Task.Delay(yourValue);
现在需要分钟。循环需要10秒。
代码:
while (true) {
// Long-poll the API
StopWatch sw = StopWatch.StartNew();
var response = await http.GetAsync(buildUri());
Console.WriteLine("Resp: " + response.ToString());
Console.WriteLine("CONTENT:");
Console.WriteLine(await response.Content.ReadAsStringAsync());
int milliseconds = 10000 - sw.ElapsedMilliSeconds;
if (milliseconds > 0)
{
await Task.Delay(milliseconds);
}
}
答案 2 :(得分:3)
您可以为此使用简单的StopWatch
,然后使用Task.Delay
等待所需的时间。
const int minimumTime = 10_000;
var sw = StopWatch.StartNew();
while (true)
{
// Long-poll the API
var response = await http.GetAsync(buildUri());
...
int difference = minimumTime - sw.EllapsedMiliseconds;
if (difference > 0)
{
await Task.Delay(difference);
}
sw.Restart();
}
但是,这仅适用于每次通话之间需要10秒的情况。如果API需要9秒钟才能完成,那么您一秒钟就会收到2次调用。
如果您希望始终等待10秒,而不考虑API完成了多少操作,只需使用:
const int waitTime = 10_000;
while (true)
{
// Long-poll the API
var response = await http.GetAsync(buildUri());
...
await Task.Delay(waitTime);
}
答案 3 :(得分:1)
不确定这是否正是您要查找的内容,但是Task.Delay可以将循环暂停给定的毫秒数。
while (true)
{
...
await Task.Delay(10 * 1000);
}
答案 4 :(得分:1)
您可以结合使用CancellationTokenSource
和TaskCompletionSource
来创建一个“延迟”任务,该任务在请求开始时开始,并在请求完成时等待:
private static Task GetDelayTask(TimeSpan delay, object state = null)
{
var taskSource = new TaskCompletionSource<object>();
var cts = new CancellationTokenSource(delay);
cts.Token.Register(() =>
{
taskSource.SetResult(state);
cts.Dispose();
});
return taskSource.Task;
}
用法:
HttpClient http = new HttpClient();
while (true)
{
var delayTask = GetDelayTask(TimeSpan.FromSeconds(10));
// Long-poll the API
var response = await http.GetAsync(buildUri());
Console.WriteLine("Resp: " + response.ToString());
Console.WriteLine("CONTENT:");
Console.WriteLine(await response.Content.ReadAsStringAsync());
await delayTask;
}