回顾
上一篇文章讲解了最原始的异步调用方式,BeginInvoke和EndInvoke方法是.NET中用于实现异步编程的一种较旧的方式,不建议再使用。它们通常用于以下场景:。
- 遗留API和组件:在.NET的早期版本中,许多API和组件使用BeginInvoke和EndInvoke来支持异步操作。如果你正在使用或维护遗留代码,可能会遇到需要使用这些方法的情况;
- 不支持Task的组件:对于一些不支持Task类的旧组件或第三方库,BeginInvoke和EndInvoke可能是实现异步操作的唯一选择;
- 需要同步上下文回调:在某些情况下,当需要保持UI线程的同步上下文时(如在Windows Forms应用程序中),BeginInvoke和EndInvoke可以用于在UI线程上执行回调;
- 不支持async和await的编程语言:在VB.NET的早期版本(直到VB.NET 7)中,BeginInvoke和EndInvoke是支持异步编程的主要方式,因为当时VB.NET不支持async和await关键字;
异步调用方式(二):ThreadPool
在C#中,ThreadPool 是用于管理工作线程的池。使用 ThreadPool 可以有效地管理线程资源,尤其是在需要处理大量短生命周期的异步操作时。下面是一个简单的例子,演示了如何使用 ThreadPool 来执行异步操作。这个例子中,我们将创建一个简单的任务,该任务将使用 ThreadPool 异步执行,并输出一些信息。
using System;
using System.Threading;
class Program
{
static void Main()
{
// 将工作项排队到线程池
ThreadPool.QueueUserWorkItem((state) =>
{
Console.WriteLine("线程池线程ID:{0}", Thread.CurrentThread.ManagedThreadId);
// 模拟一些工作
Thread.Sleep(1000);
Console.WriteLine("工作完成");
});
Console.WriteLine("主线程继续执行其他任务...");
// 主线程继续执行
Thread.Sleep(2000); // 等待一段时间以确保线程池任务完成
Console.WriteLine("主线程结束");
}
}
在这个例子中:
1.ThreadPool.QueueUserWorkItem 方法用于将一个工作项排队到线程池。这个方法接受一个 WaitCallback 委托,该委托指向要执行的方法。
2.我们定义了一个匿名方法(state 参数当前未被使用),该方法将在线程池线程上执行。在这个方法中,我们首先输出当前线程的ID,然后模拟一些工作(通过 Thread.Sleep 方法)。
3.在 Main 方法中,我们调用 ThreadPool.QueueUserWorkItem 后,主线程继续执行,输出一条消息,然后等待2秒钟。
4.当线程池线程完成工作时,它将输出“工作完成”。这个例子展示了如何使用 ThreadPool 来执行异步操作,而不会阻塞主线程。在实际应用中,这种方法对于执行IO密集型或网络操作等可能需要较长时间才能完成的任务特别有用。
ThreadPool是.NET中用于执行后台操作的一种机制。使用ThreadPool的情况通常包括:
1.简短的、频繁的任务:当需要执行大量简短的任务时,ThreadPool可以高效地重用线程,减少线程创建和销毁的开销。
2.不需要返回值的操作:ThreadPool适用于执行不需要返回值的操作,因为ThreadPool.QueueUserWorkItem方法不提供直接返回结果的方式。
3.简单的后台处理:当需要执行一些简单的后台处理,如日志记录、缓存更新等,ThreadPool是一个轻量级的选择。
4.不涉及UI的异步操作:对于不涉及更新UI的后台操作,ThreadPool是一个有效的选择。
在.NET早期版本中:在.NET Framework的早期版本(如.NET 2.0)中,ThreadPool是执行异步操作的主要方式之一。
异步调用方式(三):BackgroundWorker
BackgroundWorker 是 .NET Framework 提供的一个组件,用于在单独的线程上执行耗时的操作,同时可以与用户界面线程通信。以下是一个简单的示例,演示了如何使用 BackgroundWorker 来执行异步操作,并在操作完成后更新用户界面。
在这个例子中,我们将创建一个简单的Windows Forms应用程序。BackgroundWorker 将在后台线程上执行一个耗时操作(例如,模拟一个长时间运行的任务),并在操作完成时更新主窗体上的标签。
首先,创建一个新的Windows Forms应用程序项目。在Visual Studio中,选择“文件” > “新建” > “项目”,然后选择“Windows Forms App (.NET Framework)”作为项目类型。
接下来,将以下代码添加到您的项目中:
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace BackgroundWorkerExample
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load(object sender, EventArgs e)
{
// 创建 BackgroundWorker 实例
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
// 绑定事件处理程序
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
// 启动 BackgroundWorker
worker.RunWorkerAsync();
}
// 耗时操作在这里执行
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i <= 100; i++)
{
// 模拟耗时操作
Thread.Sleep(100);
// 报告进度
((BackgroundWorker)sender).ReportProgress(i);
// 检查是否已请求取消
if (((BackgroundWorker)sender).CancellationPending)
{
e.Cancel = true;
break;
}
}
}
// 更新进度条
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
}
// 操作完成后执行
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
labelStatus.Text = "操作已取消";
}
else
{
labelStatus.Text = "操作已完成";
}
}
}
}
然后,在主窗体上添加以下控件:
- 一个 ProgressBar 控件,用于显示操作的进度。
- 一个 Label 控件,用于显示操作的状态(例如,“操作已完成”或“操作已取消”)。
确保将 BackgroundWorker 相关的事件处理程序绑定到正确的控件和事件。
现在,当您运行应用程序时,BackgroundWorker 将在后台线程上执行耗时操作,并定期更新进度条。您还可以通过调用 BackgroundWorker.CancelAsync 方法来取消正在进行的操作。
BackgroundWorker类在.NET中用于在单独的线程上执行耗时操作,同时能够与UI线程通信。它适用于以下场景:
1.Windows Forms应用程序:在Windows Forms应用程序中,BackgroundWorker是一个常用的工具,用于在后台执行长时间运行的任务,同时保持UI响应。
2.需要更新UI的操作:如果你的后台任务需要定期更新UI(例如,显示进度条或状态信息),BackgroundWorker可以很容易地实现这一点。它提供了ProgressChanged事件,可以用来更新UI。
3.简单的并行处理:对于不需要复杂线程管理的简单并行处理,BackgroundWorker是一个不错的选择。
4.需要取消操作:BackgroundWorker支持取消操作。如果用户需要能够取消长时间运行的任务,这是一个很好的选择。
5.操作完成后需要处理结果:BackgroundWorker在操作完成后会触发RunWorkerCompleted事件,在这里可以处理任务的结果。
6.不支持异步编程的语言:在VB.NET中,BackgroundWorker是支持异步编程的主要方式,因为VB.NET直到版本7才引入了async和await关键字。
异步调用方式(四):Task
Task 类是 .NET Framework 4 引入的,用于表示异步操作。以下是一个简单的示例,演示了如何使用 Task 来执行异步操作。这个例子中,我们将创建一个简单的 Task,该 Task 将执行一个耗时操作(例如,模拟一个长时间运行的任务),并在操作完成后输出一些信息。
using System;
using System.Threading.Tasks;
class Program
{
static void Main()
{
// 创建 Task
Task task = new Task(() =>
{
Console.WriteLine("Task 开始执行");
// 模拟一些工作
Thread.Sleep(2000);
Console.WriteLine("Task 完成执行");
});
// 启动 Task
task.Start();
// 等待 Task 完成
task.Wait();
Console.WriteLine("主线程继续执行...");
}
}
在这个例子中:
1.我们创建了一个新的 Task 对象。这个 Task 执行一个简单的操作:首先输出一条消息,然后等待2秒钟,最后再输出一条消息。
2.使用 task.Start() 方法启动 Task。这将在线程池线程上异步执行 Task 的主体。
3.使用 task.Wait() 方法等待 Task 完成。这会导致主线程阻塞,直到 Task 完成为止。
4.当 Task 完成后,主线程继续执行,并输出一条消息。
这个例子展示了如何使用 Task 来执行异步操作,在实际应用中,这种方法对于执行IO密集型或网络操作等可能需要较长时间才能完成的任务特别有用。
Task类是.NET Framework中异步编程模型(TAP)的核心。使用Task类的情况通常包括:
1.现代异步编程:当使用C# 5.0或更高版本时,async和await关键字与Task类结合使用,提供了简洁、易读的异步编程模型。
2.不需要UI交互的后台操作:对于不涉及UI更新的后台操作,Task是一个轻量级的选择。
3.复杂的异步控制:如果需要更细粒度的控制,如任务取消、延续、等待多个任务完成等,Task提供了丰富的API来实现这些功能。
4.并行处理:Task可以很容易地用于并行处理多个操作,尤其是使用Task.WhenAll和Task.WhenAny等方法。
5.创建延续任务:当一个任务的完成需要启动另一个任务时,Task的延续功能非常有用。
6.在现代应用程序中:对于ASP.NET Core、.NET Core和最新的.NET应用程序,Task是推荐使用的异步编程方式。
下一篇我们讲解异步调用的最后一种方式:async和await关键字