【发布时间】:2019-01-05 01:37:21
【问题描述】:
我正在使用可观察/反应式扩展来消除某些事件,例如按钮单击或在文本框中输入文本。但是,在关机或关闭的情况下,我需要等待任何未决事件,以便保存操作可以完成,等等。
下面的代码会死锁。
Button b1 = new Button();
var scheduler = new EventLoopScheduler(ts => new Thread(ts)
{
IsBackground = false
});
var awaiter = Observable.FromEventPattern(h => b1.Click += h, h => b1.Click -= h, scheduler)
.Throttle(TimeSpan.FromMilliseconds(5000), scheduler)
.FirstOrDefaultAsync();
someTaskList.add(awaiter.ToTask());
awaiter.Subscribe
(
x =>
{
//do some work in response to click event
}
);
//program continues...
然后,在应用程序的其他地方
private async Task CloseApplicationSafely()
{
await AwaitPendingEvents();
}
private async Task AwaitPendingEvents()
{
if(someTaskList.Count > 0)
{
await Task.WhenAll(someTaskList);
}
}
然后程序将死锁,如果按钮点击从未发生,则永远等待。这是另一个示例,但带有一个文本框。
var completedTask = Observable.FromEventPattern(h => t1.TextChanged += h, h => t1.TextChanged -= h, scheduler)
.Select(x => ((TextBox)x.Sender).Text)
.DistinctUntilChanged()
.Throttle(TimeSpan.FromMilliseconds(5000), scheduler)
.ForEachAsync(txt =>
{
//do some work, save the text
});
someTaskList.Add(completedTask);
在这种情况下,文本是否被更改并不重要。如果您等待,变量 completedTask 将永远死锁。 ForEachAsync() 返回一个似乎永远不会被激活的任务。
我做错了什么?希望我的预期功能很明确。我正在消除事件。但我需要等待任何正在处理的未决事件以确保它们完成。如果没有待处理的事件,则无需等待即可继续。谢谢。
【问题讨论】:
-
您能说明什么是待处理事件吗?待处理事件的来源在哪里?
-
我不确定我是否理解您的问题。见源。 Observable 绑定到像 Click 或 TextChanged 这样的控制事件。然后使用 Throttle() 消除这些事件。因此,您可以多次快速触发单击该按钮,但它会等到您最后一次单击后的 5 秒,然后再通过订阅触发单个事件。这就是我所说的待处理事件。有人点击了,但订阅尚未执行。
-
这不是死锁。死锁是一种循环依赖。 A 在等待 B,B 在等待 A,所以他们永远无法完成,因为他们都不会让对方完成。你只是在等待永远不会完成的事情,但永远不会完成的事情不依赖于其他任何东西,它只是永远不会完成的事情。这是一个重要的区别,因为它们的解决方式不同。对于死锁,您删除循环依赖,对于永远不会完成的任务,您要么需要强制它完成,要么在等待之前检查它是否会完成。
-
当你希望程序结束时,你需要有可观察的结束。尝试使用
.Take或.TakeUntil来做。
标签: c# observable system.reactive