C# 每个迭代的速率限制

C# 每个迭代的速率限制,c#,system.reactive,rate-limiting,C#,System.reactive,Rate Limiting,基本上,我试图限制列表迭代的执行 我真的很喜欢使用RX的想法,因为我可以在RX的基础上构建它,并且有一个更优雅的解决方案,但它不必使用RX 我在许多比我聪明得多的人的帮助下制定了这个公式。我的问题是我想说一些Collection.RateLimitedForEach(速率,函数),并让它最终阻止,直到我们完成处理。。。或者让它成为一个异步方法 函数下面的演示在控制台应用程序中工作,但如果我在foreach之后关闭,它会立即返回 我只是有点不知所措,这是可以解决的,还是应该完全不同 public

基本上,我试图限制列表迭代的执行

我真的很喜欢使用RX的想法,因为我可以在RX的基础上构建它,并且有一个更优雅的解决方案,但它不必使用RX

我在许多比我聪明得多的人的帮助下制定了这个公式。我的问题是我想说一些Collection.RateLimitedForEach(速率,函数),并让它最终阻止,直到我们完成处理。。。或者让它成为一个异步方法

函数下面的演示在控制台应用程序中工作,但如果我在foreach之后关闭,它会立即返回

我只是有点不知所措,这是可以解决的,还是应该完全不同

public static void RateLimitedForEach<T>(this List<T> list, double minumumDelay, Action<T> action)
{
    list.ToObservable().Zip(Observable.Interval(TimeSpan.FromSeconds(minumumDelay)), (v, _) => v)
    .Do(action).Subscribe();
}

//rate limits iteration of foreach... keep in mind this is not the same thing as just sleeping for a second
//between each iteration, this is saying at the start of the next iteration, if minimum delay time hasnt past, hold until it has
var maxRequestsPerMinute = 60;
requests.RateLimitedForeach(60/maxRequestsPerMinute,(request) =>   SendRequest(request));
public static void rate limitedforeach(此列表,双分钟延迟,操作)
{
list.ToObservable().Zip(Observable.Interval(TimeSpan.FromSeconds(minumdelay)),(v,)=>v)
.Do(action.Subscribe();
}
//速率限制foreach的迭代。。。记住,这和睡一秒钟不是一回事
//在每次迭代之间,这意味着在下一次迭代开始时,如果最小延迟时间还没有过去,则保持到它过去为止
var maxRequestsPerMinute=60;
requests.RateLimitedForeach(60/maxRequestsPerMinute,(请求)=>SendRequest(请求));
但它不必使用RX来完成

以下是如何同步执行此操作:

public static void RateLimitedForEach<T>(
    this List<T> list,
    double minumumDelay,
    Action<T> action)
{
    foreach (var item in list)
    {
        Stopwatch sw = Stopwatch.StartNew();

        action(item);

        double left = minumumDelay - sw.Elapsed.TotalSeconds;

        if(left > 0)
            Thread.Sleep(TimeSpan.FromSeconds(left));
    }
}
另一方面,如果您在异步方法中,则需要异步等待,如下所示:

public static async Task RateLimitedForEachAsync<T>(
    this List<T> list,
    double minumumDelay,
    Func<T,Task> async_task_func)
{
    foreach (var item in list)
    {
        Stopwatch sw = Stopwatch.StartNew();

        await async_task_func(item);

        double left = minumumDelay - sw.Elapsed.TotalSeconds;

        if (left > 0)
            await Task.Delay(TimeSpan.FromSeconds(left));

    }
}    
List<string> list = new List<string>();

list.Add("1");
list.Add("2");

var task = list.RateLimitedForEachAsync(1.0, async str =>
{
    //Do something asynchronous here, e.g.:
    await Task.Delay(500);
    Console.WriteLine(DateTime.Now + ": " + str);
});
task.Wait();
await task;
但它不必使用RX来完成

以下是如何同步执行此操作:

public static void RateLimitedForEach<T>(
    this List<T> list,
    double minumumDelay,
    Action<T> action)
{
    foreach (var item in list)
    {
        Stopwatch sw = Stopwatch.StartNew();

        action(item);

        double left = minumumDelay - sw.Elapsed.TotalSeconds;

        if(left > 0)
            Thread.Sleep(TimeSpan.FromSeconds(left));
    }
}
另一方面,如果您在异步方法中,则需要异步等待,如下所示:

public static async Task RateLimitedForEachAsync<T>(
    this List<T> list,
    double minumumDelay,
    Func<T,Task> async_task_func)
{
    foreach (var item in list)
    {
        Stopwatch sw = Stopwatch.StartNew();

        await async_task_func(item);

        double left = minumumDelay - sw.Elapsed.TotalSeconds;

        if (left > 0)
            await Task.Delay(TimeSpan.FromSeconds(left));

    }
}    
List<string> list = new List<string>();

list.Add("1");
list.Add("2");

var task = list.RateLimitedForEachAsync(1.0, async str =>
{
    //Do something asynchronous here, e.g.:
    await Task.Delay(500);
    Console.WriteLine(DateTime.Now + ": " + str);
});
task.Wait();
await task;

RX油门是否不符合您的要求


RX油门是否不满足您的要求


获取accross所需的概念是,主线程不会等待
RateLimitedForEach
调用完成。此外,在你的控制台应用程序上,主线程一结束,进程就结束了

这是什么意思?这意味着无论
RateLimitedForEach
上的观察者是否已完成执行,该过程都将结束

注意:用户可能仍然会强制执行您的应用程序,这是一件好事。如果希望能够在不挂起UI的情况下等待,则可以使用表单应用;如果不希望用户关闭与流程相关的窗口,则可以使用服务


使用任务是我在下面介绍的一个重要方面

请注意,在console应用程序上使用任务时,您仍然需要等待任务,以防止主线程在
RateLimitedForEach
完成其作业之前完成。仍然建议远离控制台应用程序


如果您坚持继续使用代码,您可以调整代码使其挂起调用线程,直到完成:

public static void RateLimitedForEach<T>
(
    this List<T> list,
    double minumumDelay,
    Action<T> action
)
{
    using (var waitHandle = new ManualResetEventSlim(false))
    {

        var mainObservable = list.ToObservable();
        var intervalObservable = Observable.Interval(TimeSpan.FromSeconds(minumumDelay));  
        var zipObservable = mainObservable .Zip(intervalObservable, (v, _) => v);
        zipObservable.Subscribe
        (
            action,
            error => GC.KeepAlive(error), // Ingoring them, as you already were
            () => waitHandle.Set() // <-- "Done signal"
        );

        waitHandle.Wait(); // <--- Waiting on the observer to complete
    }
}
公共静态无效率限制为每个
(
这个名单,,
双分钟延迟,
行动
)
{
使用(var waitHandle=new ManualResetEventSlim(错误))
{
var main observable=list.ToObservable();
var intervalObservable=可观测的时间间隔(TimeSpan.FromSeconds(MinumDelay));
var zipObservable=main observable.Zip(intervalObservable,(v,)=>v);
zipObservable.Subscribe
(
行动,
error=>GC.KeepAlive(error),//像以前一样输入它们

()=>waitHandle.Set()/您需要获得accross的概念是,主线程不会等待您的
RateLimitedForEach
调用完成。此外,在您的控制台应用程序上,主线程一结束,进程就结束了

这意味着什么?这意味着无论
RateLimitedForEach
上的观察者是否已完成执行,进程都将结束

注意:用户可能仍然会强制完成应用程序的执行,这是一件好事。如果您希望能够在不挂起UI的情况下等待,则可以使用表单应用程序;如果您不希望用户关闭与该进程相关的窗口,则可以使用服务


使用任务是我在下面介绍的一个重要方面

请注意,在控制台应用程序上使用任务时,您仍然需要等待任务完成,以防止主线程在
RateLimitedForEach
完成其作业之前完成。建议您离开控制台应用程序


如果您坚持继续使用代码,您可以调整代码使其挂起调用线程,直到完成:

public static void RateLimitedForEach<T>
(
    this List<T> list,
    double minumumDelay,
    Action<T> action
)
{
    using (var waitHandle = new ManualResetEventSlim(false))
    {

        var mainObservable = list.ToObservable();
        var intervalObservable = Observable.Interval(TimeSpan.FromSeconds(minumumDelay));  
        var zipObservable = mainObservable .Zip(intervalObservable, (v, _) => v);
        zipObservable.Subscribe
        (
            action,
            error => GC.KeepAlive(error), // Ingoring them, as you already were
            () => waitHandle.Set() // <-- "Done signal"
        );

        waitHandle.Wait(); // <--- Waiting on the observer to complete
    }
}
公共静态无效率限制为每个
(
这个名单,,
双分钟延迟,
行动
)
{
使用(var waitHandle=new ManualResetEventSlim(错误))
{
var main observable=list.ToObservable();
var intervalObservable=可观测的时间间隔(TimeSpan.FromSeconds(MinumDelay));
var zipObservable=main observable.Zip(intervalObservable,(v,)=>v);
zipObservable.Subscribe
(
行动,
error=>GC.KeepAlive(error),//像以前一样输入它们

()=>waitHandle.Set()/您的代码非常完美

请尝试以下方法:

public static void RateLimitedForEach<T>(this List<T> list, double minumumDelay, Action<T> action)
{
    list
        .ToObservable()
        .Zip(Observable.Interval(TimeSpan.FromSeconds(minumumDelay)), (v, _) => v)
        .Do(action)
        .ToArray()
        .Wait();
}
public static void rate limitedforeach(此列表,双分钟延迟,操作)
{
列表
.TooObservable()文件
.Zip(可观察的时间间隔(时间跨度从秒(分钟延迟)),(v,)=>v)
.Do(行动)
.ToArray()
.Wait();
}

您的代码几乎完美无瑕

请尝试以下方法:

public static void RateLimitedForEach<T>(this List<T> list, double minumumDelay, Action<T> action)
{
    list
        .ToObservable()
        .Zip(Observable.Interval(TimeSpan.FromSeconds(minumumDelay)), (v, _) => v)
        .Do(action)
        .ToArray()
        .Wait();
}
public static void rate limitedforeach(此列表,双分钟延迟,操作)
{
列表
.TooObservable()文件
.Zip(可观察的时间间隔(时间跨度从秒(分钟延迟)),(v,)=>v)
.Do(行动)
.ToArray()
.Wait();
}

我注意到,删除了我的评论-因为它不再相关,我投了赞成票。我注意到,删除了我的comme