C# 由用户启动的多个线程。仅使用上一个的结果
我有一个应用程序,其中用户提供要由线程处理的数据,然后线程将数据返回到UI中。用户可以从另一个线程开始更改输入。如何正确地忽略旧的重复线程 我注意到有两种解决方案经常被描述。 1) 在调用中,检查当前输入数据是否与处理的线程相同 2) 等待第一个线程结束,然后再启动另一个线程 第一个解决方案是可行的,但若用户再次将输入更改为相同的值,并且我得到两次或更多具有相同数据的刷新UI,则可能会使用更旧的线程 第二个选项响应性较差,特别是当线程中的计算运行时间较长时,因为我们必须等待每个线程完成其工作 我创建了下面的解决方案,我想知道这是否是正确的处理方法,或者我需要添加一些其他检查或锁定C# 由用户启动的多个线程。仅使用上一个的结果,c#,C#,我有一个应用程序,其中用户提供要由线程处理的数据,然后线程将数据返回到UI中。用户可以从另一个线程开始更改输入。如何正确地忽略旧的重复线程 我注意到有两种解决方案经常被描述。 1) 在调用中,检查当前输入数据是否与处理的线程相同 2) 等待第一个线程结束,然后再启动另一个线程 第一个解决方案是可行的,但若用户再次将输入更改为相同的值,并且我得到两次或更多具有相同数据的刷新UI,则可能会使用更旧的线程 第二个选项响应性较差,特别是当线程中的计算运行时间较长时,因为我们必须等待每个线程完成其工作 我
private Thread lastThread;
private void ButtonClick(object sender, MouseButtonEventArgs e)
{
this.lastThread= new Thread(delegate () { Update(someData); });
this.lastThread.Start();
}
private void Update(int someData) {
Thread currThread = Thread.CurrentThread;
Application.Current.Dispatcher.Invoke(new Action(() => EndUpdate(
someDataCalculated,
currThread
)));
private void EndUpdate(int someDataCalculated, Thread senderThread) {
if (senderThread == this.lastThread)
{
// right thread, do some work in UI
}
}
如果用户调用了几个线程,并且可以更新其中任何线程中的数据, 我认为您应该添加一个最新更新的属性。
并跟踪用户何时进行更改,并据此比较线程。您应该使用专门设计的工具来处理此类事情,并且它是Microsoft的反应式框架 您只需编写以下代码:
public MainWindow()
{
InitializeComponent();
IDisposable subscription =
Observable
.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(
h => Button.MouseLeftButtonDown += h,
h => Button.MouseLeftButtonDown -= h)
.Select(x => Observable.Start(() => { Update(42); return 42; }))
.Switch()
.ObserveOnDispatcher()
.Subscribe(x =>
{
// latest result only, do some work in UI
});
}
public主窗口()
{
初始化组件();
IDisposable订阅=
可观察
.FromEventPattern(
h=>Button.MouseLeftButtonDown+=h,
h=>Button.MouseLeftButtonDown-=h)
.Select(x=>Observable.Start(()=>{Update(42);return 42;}))
.Switch()
.ObserveOnDispatcher()
.订阅(x=>
{
//仅限最新结果,在UI中执行一些工作
});
}
这通过调用Update(42)响应MouseLeftButtonDown
事件;返回42代码>在后台线程上。然后它调用.Switch()
,这是一个特殊的操作符,确保只返回对可观察的最新调用的结果。返回Start(()=>{Update(42);return 42;})
(它忽略以前的任何一个,不管它们是否先出现)。然后,它使用.ObserveOnDispatcher()
操作符将数据编组回UI。最后,.Subscribe(x=>
允许UI响应UI线程上的返回值
请记住,问题中的示例代码没有完全充实,所以我对它进行了一些捏造,但我想你明白了
在订阅上调用.Dispose()
会分离事件处理
只需NuGet“System.Reactive.Windows.Threading”来获取位,并使用System.Reactive.Linq;
将添加到代码中,以获得所需的扩展方法
如果需要进一步解释,请告诉我。如果可能,我建议使用带有CancellationToken
的任务
。请注意,取消是合作的。如果此任务在计算上非常昂贵,您确定要给用户创建所需数量的任务的能力吗?一些用户会向您知道的按钮发送垃圾邮件w、 这类似于自动完成功能。用户可以键入许多字母,在提供响应之前,您不会阻止输入下一个字母。而是会应用一些延迟来防止产生太多线程。我不能使用task,因为在我的情况下线程必须是STA。我也有点担心取消令牌可能由于调用而无法工作到主线程。所以我可以检查它的状态的最后一个地方是在调用之前,而调用可能会等待到UI线程,在那个里用户可能会启动一个新线程。如何正确地忽略旧的重试线程?
向每个请求传递一个int
值参数。为每个请求递增它。跟踪int
的最新的响应。忽略任何响应
,其中int
在最新响应之前。您可能需要一个锁
来处理同时出现的两个响应。