C# 什么';使用Rx运行周期性任务的一个好方法是什么,只有一个并发执行限制?
我希望在中运行周期性任务,限制在任何给定时间内最多只能运行一次方法执行 我正在试验Rx,但我不确定如何最多施加一次并发限制C# 什么';使用Rx运行周期性任务的一个好方法是什么,只有一个并发执行限制?,c#,system.reactive,rx.net,C#,System.reactive,Rx.net,我希望在中运行周期性任务,限制在任何给定时间内最多只能运行一次方法执行 我正在试验Rx,但我不确定如何最多施加一次并发限制 var timer = Observable.Interval(TimeSpan.FromMilliseconds(100)); timer.Subscribe(tick => DoSomething()); 此外,如果任务仍在运行,则我希望后续的计划将过期。i、 e我不希望任务排队并导致问题 我有两个这样的任务要定期执行。当前正在执行的任务是同步的。但是,如果有
var timer = Observable.Interval(TimeSpan.FromMilliseconds(100));
timer.Subscribe(tick => DoSomething());
此外,如果任务仍在运行,则我希望后续的计划将过期。i、 e我不希望任务排队并导致问题
我有两个这样的任务要定期执行。当前正在执行的任务是同步的。但是,如果有必要的话,我可以使它们异步。如果你走的是正确的道路,你可以使用
选择+Concat
来平展可观察到的内容,并限制机上请求的数量(注意:如果你的任务花费的时间超过了间隔时间,那么它们将开始堆积,因为它们无法足够快地执行):
您走在正确的轨道上,您可以使用Select
+Concat
来平展可观察到的数据并限制机上请求的数量(注意:如果您的任务花费的时间超过了间隔时间,那么它们将开始堆积,因为它们无法足够快地执行):
您应该按原样测试您的代码,因为这正是Rx已经实施的
尝试以下测试:
void Main()
{
var timer = Observable.Interval(TimeSpan.FromMilliseconds(100));
using (timer.Do(x => Console.WriteLine("!")).Subscribe(tick => DoSomething()))
{
Console.ReadLine();
}
}
private void DoSomething()
{
Console.Write("<");
Console.Write(DateTime.Now.ToString("HH:mm:ss.fff"));
Thread.Sleep(1000);
Console.WriteLine(">");
}
void Main()
{
var定时器=可观察的时间间隔(TimeSpan.From毫秒(100));
使用(timer.Do(x=>Console.WriteLine(!)).Subscribe(tick=>DoSomething())
{
Console.ReadLine();
}
}
私人无效剂量()
{
控制台。写(“”);
}
运行此命令时,您将获得以下类型的输出:
!
<16:54:57.111>
!
<16:54:58.112>
!
<16:54:59.113>
!
<16:55:00.113>
!
<16:55:01.114>
!
<16:55:02.115>
!
<16:55:03.116>
!
<16:55:04.117>
!
<16:55:05.118>
!
<16:55:06.119
!
!
!
!
!
!
!
!
!
!
您应该按原样测试您的代码,因为这正是Rx已经实施的
尝试以下测试:
void Main()
{
var timer = Observable.Interval(TimeSpan.FromMilliseconds(100));
using (timer.Do(x => Console.WriteLine("!")).Subscribe(tick => DoSomething()))
{
Console.ReadLine();
}
}
private void DoSomething()
{
Console.Write("<");
Console.Write(DateTime.Now.ToString("HH:mm:ss.fff"));
Thread.Sleep(1000);
Console.WriteLine(">");
}
void Main()
{
var定时器=可观察的时间间隔(TimeSpan.From毫秒(100));
使用(timer.Do(x=>Console.WriteLine(!)).Subscribe(tick=>DoSomething())
{
Console.ReadLine();
}
}
私人无效剂量()
{
控制台。写(“”);
}
运行此命令时,您将获得以下类型的输出:
!
<16:54:57.111>
!
<16:54:58.112>
!
<16:54:59.113>
!
<16:55:00.113>
!
<16:55:01.114>
!
<16:55:02.115>
!
<16:55:03.116>
!
<16:55:04.117>
!
<16:55:05.118>
!
<16:55:06.119
!
!
!
!
!
!
!
!
!
!
这里有一个工厂函数,它完全满足您的要求
public static IObservable<Unit> Periodic(TimeSpan timeSpan)
{
return Observable.Return(Unit.Default).Concat(Observable.Return(Unit.Default).Delay(timeSpan).Repeat());
}
如果运行此命令,每个控制台打印的间隔大约为1.5秒
注意,如果您不想立即运行第一个勾号,您可以使用此工厂,它在时间跨度之后才会发送第一个单元
public static IObservable<Unit> DelayedPeriodic(TimeSpan timeSpan)
{
return Observable.Return(Unit.Default).Delay(timeSpan).Repeat();
}
公共静态IObservable DelayedPeriodic(TimeSpan TimeSpan)
{
return Observable.return(Unit.Default).Delay(timeSpan.Repeat();
}
这是一个工厂函数,它完全满足您的要求
public static IObservable<Unit> Periodic(TimeSpan timeSpan)
{
return Observable.Return(Unit.Default).Concat(Observable.Return(Unit.Default).Delay(timeSpan).Repeat());
}
如果运行此命令,每个控制台打印的间隔大约为1.5秒
注意,如果您不想立即运行第一个勾号,您可以使用此工厂,它在时间跨度之后才会发送第一个单元
public static IObservable<Unit> DelayedPeriodic(TimeSpan timeSpan)
{
return Observable.Return(Unit.Default).Delay(timeSpan).Repeat();
}
公共静态IObservable DelayedPeriodic(TimeSpan TimeSpan)
{
return Observable.return(Unit.Default).Delay(timeSpan.Repeat();
}
下面是PeriodicSequentialExecution
方法的两个实现,该方法通过以周期性方式执行异步方法,强制执行无重叠执行策略来创建一个可观察的。后续执行之间的间隔可以延长,以防止重叠,在这种情况下,周期会相应地进行时间偏移
第一个实现纯粹是功能性的,而第二个实现主要是必需的。两种实现在功能上完全相同。第一个可以与自定义的IScheduler
一起提供。第二种可能会稍微有效一些
功能实现:
/// <summary>
/// Creates an observable sequence containing the results of an asynchronous
/// action that is invoked periodically and sequentially (without overlapping).
/// </summary>
public static IObservable<T> PeriodicSequentialExecution<T>(
Func<CancellationToken, Task<T>> action,
TimeSpan dueTime, TimeSpan period,
CancellationToken cancellationToken = default,
IScheduler scheduler = null)
{
// Arguments validation omitted
scheduler ??= DefaultScheduler.Instance;
return Delay(dueTime) // Initial delay
.Concat(Observable.Using(() => CancellationTokenSource.CreateLinkedTokenSource(
cancellationToken), linkedCTS =>
// Execution loop
Observable.Publish( // Start a hot delay timer before each operation
Delay(period), hotTimer => Observable
.StartAsync(() => action(linkedCTS.Token)) // Start the operation
.Concat(hotTimer) // Await the delay timer
)
.Repeat()
.Finally(() => linkedCTS.Cancel()) // Unsubscription: cancel the operation
));
IObservable<T> Delay(TimeSpan delay)
=> Observable
.Timer(delay, scheduler)
.IgnoreElements()
.Select(_ => default(T))
.TakeUntil(Observable.Create<Unit>(o => cancellationToken.Register(() =>
o.OnError(new OperationCanceledException(cancellationToken)))));
}
public static IObservable<T> PeriodicSequentialExecution2<T>(
Func<CancellationToken, Task<T>> action,
TimeSpan dueTime, TimeSpan period,
CancellationToken cancellationToken = default)
{
// Arguments validation omitted
return Observable.Create<T>(async (observer, ct) =>
{
using (var linkedCTS = CancellationTokenSource.CreateLinkedTokenSource(
ct, cancellationToken))
{
try
{
await Task.Delay(dueTime, linkedCTS.Token);
while (true)
{
var delayTask = Task.Delay(period, linkedCTS.Token);
var result = await action(linkedCTS.Token);
observer.OnNext(result);
await delayTask;
}
}
catch (Exception ex) { observer.OnError(ex); }
}
});
}
//
///创建一个可观察序列,其中包含异步
///定期和顺序调用的操作(没有重叠)。
///
公共静态可观测周期SequentialExecution(
Func action,
TimeSpan dueTime,TimeSpan期间,
CancellationToken CancellationToken=默认值,
isScheduler调度程序(0=null)
{
//省略参数验证
调度器???=DefaultScheduler.Instance;
返回延迟(dueTime)//初始延迟
.Concat(可观察。使用(()=>CancellationTokenSource.CreateLinkedTokenSource(
cancellationToken),linkedCTS=>
//执行循环
Observable.Publish(//在每次操作之前启动热延迟计时器
延迟(周期),热定时器=>可观察
.StartAsync(()=>action(linkedCTS.Token))//启动操作
.Concat(hotTimer)//等待延迟计时器
)
.重复
.Finally(()=>linkedCTS.Cancel())//取消订阅:取消操作
));
IO可观测延迟(时间跨度延迟)
=>可观测
.计时器(延迟、调度程序)
.IgnoreElements()
.选择(=>default(T))
.TakeUntil(Observable.Create(o=>cancellationToken.Register)(()=>
o、 OnError(新操作取消异常(取消令牌()())));
}
当务之急是执行:
/// <summary>
/// Creates an observable sequence containing the results of an asynchronous
/// action that is invoked periodically and sequentially (without overlapping).
/// </summary>
public static IObservable<T> PeriodicSequentialExecution<T>(
Func<CancellationToken, Task<T>> action,
TimeSpan dueTime, TimeSpan period,
CancellationToken cancellationToken = default,
IScheduler scheduler = null)
{
// Arguments validation omitted
scheduler ??= DefaultScheduler.Instance;
return Delay(dueTime) // Initial delay
.Concat(Observable.Using(() => CancellationTokenSource.CreateLinkedTokenSource(
cancellationToken), linkedCTS =>
// Execution loop
Observable.Publish( // Start a hot delay timer before each operation
Delay(period), hotTimer => Observable
.StartAsync(() => action(linkedCTS.Token)) // Start the operation
.Concat(hotTimer) // Await the delay timer
)
.Repeat()
.Finally(() => linkedCTS.Cancel()) // Unsubscription: cancel the operation
));
IObservable<T> Delay(TimeSpan delay)
=> Observable
.Timer(delay, scheduler)
.IgnoreElements()
.Select(_ => default(T))
.TakeUntil(Observable.Create<Unit>(o => cancellationToken.Register(() =>
o.OnError(new OperationCanceledException(cancellationToken)))));
}
public static IObservable<T> PeriodicSequentialExecution2<T>(
Func<CancellationToken, Task<T>> action,
TimeSpan dueTime, TimeSpan period,
CancellationToken cancellationToken = default)
{
// Arguments validation omitted
return Observable.Create<T>(async (observer, ct) =>
{
using (var linkedCTS = CancellationTokenSource.CreateLinkedTokenSource(
ct, cancellationToken))
{
try
{
await Task.Delay(dueTime, linkedCTS.Token);
while (true)
{
var delayTask = Task.Delay(period, linkedCTS.Token);
var result = await action(linkedCTS.Token);
observer.OnNext(result);
await delayTask;
}
}
catch (Exception ex) { observer.OnError(ex); }
}
});
}
公共静态可观察周期SequentialExecution2(
Func action,
TimeSpan dueTime,TimeSpan期间,
CancellationToken CancellationToken=默认值)
{
//省略参数验证
返回可观察的。创建(异步(观察者,ct)=>
{
使用(var linkedCTS=CancellationTokenSource.CreateLinkedTokenSource(
ct,取消令牌)
{
尝试
{
等待任务延迟(dueTime,linkedCTS.Token);
while(true)
{
var delayTask=Task.Delay(period,linkedCTS.Token);
var result=等待操作(linkedCTS.Token);
OnNext观察员(结果);
等待任务的完成;