从额外的线程返回结果

本文关键字:返回 结果 线程 | 更新日期: 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:

使用新的asyncawait关键字。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()

希望这有帮助。