我有一个长期运行的任务(使用Kinect One从深度图像创建纹理),它是使用Reactive Extensions实现的。它的要点如下:
kinectWrapper.DepthFrames
.ObserveOn(new EventLoopScheduler())
.Select(f => do some CPU intensive data manipulation to create the color texture I want)
.Subscribe(colorFrame => fill texture on GPU)
问题是选择和订阅在系统上都很重,并且不会全速运行。我已经设法在我的开发PC上以.Sample(TimeSpan.FromMilliseconds(100))
以可接受的速度运行它,但我宁愿让它根据CPU使用率降低帧速率。
我认为有两种可能性:
答案 0 :(得分:2)
可以通过修改此处的扩展方法的行为来实现解决方案:http://rxx.codeplex.com/workitem/20724
下面是一个例子。在这种情况下,我修改了行为,以便扩展方法通过丢弃最旧的通知来限制排队通知的数量,直到队列大小可以接受为止。
为了满足您的要求,您可以对其进行修改,以便根据您可以使用System.Diagnostics.PerformanceCounter类读取的CPU指标丢弃某些通知。
但是,您也可以尝试从这些具体细节中抽象出来,也许您可以使用下面的扩展方法和使用低优先级线程的调度程序。
这意味着当CPU忙时,通知更有可能被丢弃。
kinectWrapper.DepthFrames.ThrottledObserveOn(
new EventLoopScheduler(start => new Thread(start) {Priority = ThreadPriority.Lowest, IsBackground = true}),
5).Select(...
public static IObservable<TSource> ThrottledObserveOn<TSource>(
this IObservable<TSource> source,
IScheduler scheduler,
int maximumQueuedNotifications)
{
Contract.Requires(source != null);
Contract.Requires(scheduler != null);
Contract.Requires(maximumQueuedNotifications >= 0);
return Observable.Create<TSource>(observer =>
{
var notificationsGate = new object();
var acceptingNotification = false;
var nextNotifications = new Queue<Notification<TSource>>();
Notification<TSource> completionNotification = null;
var schedulerDisposable = new MultipleAssignmentDisposable();
var subscriptionDisposable = source.Materialize().Subscribe(notification =>
{
bool startAcceptingNotifications;
lock (notificationsGate)
{
startAcceptingNotifications = !acceptingNotification;
acceptingNotification = true;
if (notification.Kind == NotificationKind.OnNext)
{
nextNotifications.Enqueue(notification);
}
else
{
completionNotification = notification;
}
}
if (startAcceptingNotifications)
{
schedulerDisposable.Disposable = scheduler.Schedule(rescheduleAction =>
{
Notification<TSource> notificationToAccept;
lock (notificationsGate)
{
if (nextNotifications.Any())
{
do
{
notificationToAccept = nextNotifications.Dequeue();
}
while (nextNotifications.Count > maximumQueuedNotifications);
}
else
{
notificationToAccept = completionNotification;
completionNotification = null;
}
}
notificationToAccept.Accept(observer);
bool continueAcceptingNotification;
lock (notificationsGate)
{
continueAcceptingNotification = acceptingNotification = nextNotifications.Any() || completionNotification != null;
}
if (continueAcceptingNotification)
{
rescheduleAction();
}
});
}
});
return new CompositeDisposable(subscriptionDisposable, schedulerDisposable);
});
}