c#异步调用的几种方式(二)(三)(四)

回顾

上一篇文章讲解了最原始的异步调用方式,BeginInvoke和EndInvoke方法是.NET中用于实现异步编程的一种较旧的方式,不建议再使用。它们通常用于以下场景:。

  1. 遗留API和组件:在.NET的早期版本中,许多API和组件使用BeginInvoke和EndInvoke来支持异步操作。如果你正在使用或维护遗留代码,可能会遇到需要使用这些方法的情况;
  2. 不支持Task的组件:对于一些不支持Task类的旧组件或第三方库,BeginInvoke和EndInvoke可能是实现异步操作的唯一选择;
  3. 需要同步上下文回调:在某些情况下,当需要保持UI线程的同步上下文时(如在Windows Forms应用程序中),BeginInvoke和EndInvoke可以用于在UI线程上执行回调;
  4. 不支持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关键字

  • 29
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Windows 应用程序编程中常见的一个模式就是,在GUI用户界面下,将耗时的文件和网络处理放入 子线程,以避免用户界面不能响应的问题。在.NET出现以前,创建线 程并监视线程结束,还要更新 界面等工作,即复杂又要手写大量代码,并且难以调试。在.NET中,程序员可以通过异步调用,使 用简单的代码完成这项工作。 .NET Framework允许异步调用任何方法。使用异步调用之前,要定义一个委托,它的方法签名要与 调用方法签名一致。.NET会自动产生此委托的BeginInvoke和EndInvoke方法。 BeginInvoke 方法用于启动异步调用。它除了具有调用方法相同的参数外,还附加了两个额外的参 数,这两个额外参数将用于回调方法。 BeginInvoke执行后立即返回,并不等待异步调用完成。 BeginInvoke返回一个IAsyncResult接口,它可以用于监视调用的进度。EndInvoke方法被用来获取 异步调用的结果。在 BeginInvoke执行以后,任何时间都可以调用EndInvoke。如果异步调用尚未完 成,EndInvoke会被阻塞,直到异步调用完成。EndInvoke带有一个IAsyncResult接口类型的参数, 并返回一个IAsyncResult接口,用来获取调用结果。 本文中的代码演示了使用BeginInvoke和EndInvoke进行异步调用种常见调用方式。在调用 BeginInvoke之后,您可以: 1.完成一些其它工作,然后调用EndInvoke,等待异步调用完成。 2.使用IAsyncResult.AsyncWaitHandle获取一个WaitHandle,使用它的WaitOne方法执行阻塞调 用,完成后再调用EndInvoke。 3.轮询BeginInvoke返回的IAsyncResult接口,在异步调用完成后,再调用EndInvoke。 4.给BeginInvoke传递一个回调方法的委托,异步调用完成后,这个回调方法会在ThreadPool线程 上执行,可以在这个方法内调用EndInvoke。 警告:异步调用完成后,必须调用EndInvoke。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值