从额外的线程返回结果
本文关键字:返回 结果 线程 | 更新日期: 2023-09-27 18:31:12
我想在额外的线程中执行Heavy Process
后使result
(繁重进程的返回结果)可访问,由于主要预期不希望在此过程中UI生效,该过程完成后可以玩result
在一些搜索中,看看我的文章,我得到有几种方法为此,请提供您知道或在类似情况下使用的最佳方法
这是我想以最佳方法处理的示例:
public ACollection DoProcess(Document docProcess)
{
ACollection result = new ACollection ();
ThreadStart threadStart = delegate
{
result = MyProcess(docProcess);
};
var threadProcess = new Thread(threadStart);
threadProcess.Start();
return result ;
}
其他可能的方法可能是IAsyncResult,后台工作线程,使用计时器并检查状态,而不是将结果返回到处理它并将其报告给UI的方法,以线程安全的方式将其直接发送到我们的UI控件...
请在类似情况下给出自己的意见和样本,提前致谢
编辑3:方法-基于布莱恩的答案
LenzCollection myResultCollection = new LenzCollection();
TaskScheduler ui = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() =>
{
myResultCollection = DoCollect(docProcess);
//Task.WaitAll();
return myResultCollection;
}).ContinueWith((task =>
{
myResultCollection = task.Result;
}), ui);
return myResultCollection;
它仍然没有等待,也不会给出预期的结果
在桌面 (WinForms/WPF) 应用中,最好和最简单的方法是 BackgroundWorker。它旨在处理此问题。
只需实现一个事件,在执行方法之前注册该事件。并让该方法在完成后引发事件。
例如:
public delegate void MyEventHandler(string result);
public class MyClass
{
public event MyEventHandler MyEvent;
private void Event(string result)
{
MyEventHandler handler = MyEvent;
if(handler != null)
handler(result);
}
public void DoSomethingLong()
{
//Do something
Event("Finish");
}
}
现在你可以像这样运行它
MyClass.Event += MyEventHandler(On_Event);
Thread t = new Thread(MyClass.DoSomethingLong);
t.Start();
void On_Event(string result)
{
//Get executed when finished;
}
调用 UI 线程的示例
void On_Event(string result)
{
if(this.InvokeRequired)
{
MyEventHandler handler = new MyEventHandler(On_Event);
Invoke(handler, new object[] { result });
return;
}
// At this point you can access your UI without having Cross-Threaded operation!
}
选项 #1:
使用 Task
类和 ContinueWith
方法。
TaskScheduler ui = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() =>
{
var result = MyProcess(docProcess);
return result.ToString();
}).ContinueWith((task =>
{
textBox1.Text = task.Result;
}, ui);
您必须记住将正确的同步上下文传递到 ContinueWith
方法中。你可以看到我是如何用ui
变量做到这一点的。
选项#2:
使用新的async
和await
关键字。1
private async void SomeButton_Click(object sender, EventArgs args)
{
textBox1.Text = await Task.Run(() =>
{
var result = MyProcess(docProcess);
return result.ToString();
});
}
显然,这对眼睛来说要容易得多,并且可以为您完成所有封送处理和同步上下文的工作。
1新关键字将在 C# 5.0 中提供,但您现在可以通过异步 CTP 使用它们。CTP 使用TaskEx
而不是Task
。
如果您使用的是 .NET Framework 4.0 or +
,则可以从 Task.ContinueWith 中的另一个线程和进程运行该进程,例如
Process pro = null;
Task.Factory.StartNew(() => {
pro =new Process(..);
pro.Start();
pro.WaitForExit();
}).ContinueWith(..process data recieved from the pro)
编辑
不要使用while(...)
,而是使用pro.WaitForExit()
希望这有帮助。