异步线程

本文关键字:线程 异步 | 更新日期: 2023-09-27 18:11:59

我想知道在哪里我可以得到多线程或异步线程的一个例子。

在我忙碌的应用程序中,我必须在应用程序的后台运行一个线程来获取一个正在变化的值。当这个值达到一定值时它就需要调用另一个函数。所有这些都必须在程序的后台运行,以便用户仍然可以在应用程序上执行其他操作。

异步线程

为了总结这些选项,我将试着在这里列出它们(也许把它变成一个社区wiki是个好主意)。

首先,你可以简单地在另一个线程中启动一个函数:

Thread t = new Thread( ThreadProc );
t.Start();
// now you can wait for thread to finish with t.Join() or just continue
// Thread.IsBackground allows to control how thread lifetime influences
// the lifetime of the application
...
static void ThreadProc() {...} // can also be non-static, but for simplicity....

那么你可以使用BackgroundWorker:

BackgroundWorker bgWorker = new BackgroundWorker();
bgWorker.DoWork += MyFunction;
bgWorker.RunWorkerAsync();
voud MyFunction(object o, DoWorkEventArgs args) {...}

您可以使用ProgressChangedRunWorkerCompleted事件来进行更多的控制(以及WorkerReportsProgress和其他属性)

另一个选择是使用ThreadPool,如果你的方法不会花费太多时间:

ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));
...
static void ThreadProc(Object stateInfo) { ... }

另一个选择是在委托上调用BeginInvoke:

public delegate int MyDelegate(...);
MyDelegate del = SomeFunction;                     
IAsyncResult ar = del.BeginInvoke(...);
int result = del.EndInvoke(ar);

这将在线程池中的一个线程上执行。如果你需要等待调用线程,你可以使用IAsyncResult.IsCompleted,但它会阻塞调用线程。

当然,你可以使用Task:

var task = Task.Factory.StartNew(() => MyMethod());

这也将在线程池中的线程上执行MyMethod,因此应用相同的警告(尽管您可以使用TaskCreationOptions.LongRunning来确保始终创建新线程)。在某些情况下(当您等待任务时),它甚至可以在同一个线程上执行,但它经过了很好的优化,因此您不应该担心。

这可能是简单与控制之间最好的权衡(当然,没有真正的"最好")。以下是好处(无耻地从Jon Skeet的回答中偷来的):

  • 添加延续(Task.ContinueWith)
  • 等待多个任务完成(全部或任何)
  • 捕获任务中的错误并稍后询问它们
  • 捕获取消(并允许您指定取消开始)
  • 可能有返回值
  • 在c# 5中使用await
  • 更好地控制调度(如果要长时间运行,在创建任务时要这样说,以便任务调度程序可以考虑到这一点)

根据您所寻求的BackgroundWorker的控制级别,可以很容易地工作,并且可以在System.ComponentModel.BackgroundWorker中找到。现在这里有一个链接到MSDN文档的主题:http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

一个简单的用例场景如下:

BackgrouWorker BG = new BackgroudWorker();
GB.DoWork += YourFunctionDelegate(object Sender, EventArgs e);
GB.RunWorkerAsync();

现在YourFunctionDelegate(object Sender,EventArgs e)应该是你想在后台运行的任何东西。但是需要遵循这个参数形式,也有大量的辅助函数与后台工作者相关联,如onProgressChanged事件,允许监控明显的进度,如果你是线程的新手,如果你试图创建自己的线程,这可能会证明是一个痛苦的开始。

如果你想更多地控制线程的执行和线程的功能,你应该看看这里的Task-Parallel-Library: http://msdn.microsoft.com/en-us/library/dd460717.aspx其中有大量关于多线程的信息。

还有一个关于如何创建c#线程的教程:http://support.microsoft.com/default.aspx?scid=kb;en-us;815804

关于。net 4.5中Windows 8异步编程的概述:

http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx

对于。net 4.0和更早的版本,你可以使用ThreadPool

    System.Threading.ThreadPool.QueueUserWorkItem(obj =>
    {
        // Do some work
        for (int i = 0; i < 1000; i++)
            Math.Sin(i);
        // Get back to the UI thread
        App.Current.MainWindow.Dispatcher.BeginInvoke(
            new Action(delegate 
            { 
                block.Text = "Done!"; 
            }));
    });

我有一篇博客文章,比较和对比了各种后台任务的实现,以及每种任务的优点和缺点。剧透:Task绝对是最好的选择。另外,我推荐Task.Run而不是TaskFactory.StartNew

如果你的后台操作是真正异步的,那么你可能根本不需要任何后台线程。LINQPad有一组async示例,这是一个很好的起点。这些章节比其他人推荐的关于线程的章节(由同一作者撰写)更加最新。