首页 > 编程语言 >C#异步和多线程的理解

C#异步和多线程的理解

时间:2024-11-06 09:22:29浏览次数:4  
标签:异步 Task C# 任务 线程 多线程 CPU

1. 异步编程(Asynchronous Programming)

异步编程是通过非阻塞方式执行任务,通常适用于I/O 密集型任务,例如文件读写、网络请求、数据库访问等。这类操作不需要占用大量 CPU 资源,而是等待外部资源(如网络或硬盘)响应。

在 C# 中,异步编程使用 asyncawait 关键字来实现。异步方法会返回 TaskTask<T>,调用 await 后,主线程可以继续执行其他代码,不会被阻塞。异步任务完成后,程序会回到 await 的位置继续执行。

异步代码示例

以下是一个使用异步编程的示例:

using System;
using System.Net.Http;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        Console.WriteLine("Starting download...");
        string content = await DownloadContentAsync("https://example.com");
        Console.WriteLine("Download completed!");
        Console.WriteLine($"Content length: {content.Length}");
    }

    static async Task<string> DownloadContentAsync(string url)
    {
        using HttpClient client = new HttpClient();
        // 异步地开始下载内容
        string content = await client.GetStringAsync(url);
        return content;
    }
}

在这个例子中,DownloadContentAsync 是一个异步方法。调用 await DownloadContentAsync(...) 后,Main 方法不会被阻塞,它会释放 CPU,等到下载完成后再继续执行。这种非阻塞模式适合 I/O 密集型任务。
这里该怎么理解,为什么不会阻塞,举个实际业务的例子,就是微信支付的接口并不马上返回支付结果,这就是没有阻塞线程,线程继续做其他事情,支付结果通过回调接口通知;那么如果不是异步会是什么样的,那就是一直等待微信支付的接口响应,这个时候线程就被阻塞了。异步可以理解成回调,进一步说.Net程序向操作系统读取文件,访问网络,什么时候读到了文件,什么时候网络有了响应再回调给.Net程序,.Net程序再启用线程池的线程继续完成回调后的任务,这也是异步后线程id会改变的原因。

2. 多线程编程(Multithreading Programming)

多线程编程是通过在多个线程上并行执行任务,适用于CPU 密集型任务,如复杂计算、数据处理等。这类操作需要充分利用 CPU 的多核心能力来同时处理多个任务。

在 C# 中,多线程编程可以通过 ThreadThreadPoolTask 等类实现。与异步不同,多线程会创建多个线程来执行不同的任务,这样多个任务可以并发运行。

多线程代码示例

以下是一个使用多线程的示例:

using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        Console.WriteLine("Starting CPU-intensive tasks...");

        // 启动两个并行任务
        Task task1 = Task.Run(() => PerformCpuIntensiveTask("Task 1"));
        Task task2 = Task.Run(() => PerformCpuIntensiveTask("Task 2"));

        // 等待任务完成
        Task.WaitAll(task1, task2);

        Console.WriteLine("All tasks completed.");
    }

    static void PerformCpuIntensiveTask(string taskName)
    {
        Console.WriteLine($"{taskName} started.");
        for (int i = 0; i < 1000000000; i++)
        {
            // 模拟计算任务
            double x = Math.Sqrt(i);
        }
        Console.WriteLine($"{taskName} completed.");
    }
}

在这个例子中,Task.Run 会在 ThreadPool 中创建并启动新的线程来执行 PerformCpuIntensiveTask,这样 Task 1Task 2 就可以并行执行,提高了 CPU 使用效率。
其实无论是时阻塞的耗时还是复杂计算的耗时,这两个都是耗时,但是这两个又有很大区别,阻塞的耗时可以通过回调,释放当前线程来解决阻塞的问题,但是复杂计算的耗时核回调就没有关系了。举个具体点的例子,要计算一个天文级别的数字,一个人要10天,但是你发现这些数子是可以拆开来分给不同的人计算,最后把结果加起来就行了。这种情况下使用多线程处理计算任务,然后把结果加起来,减少了耗时,同时也提高了cpu的使用率。

总结

  • 异步主要用于非阻塞 I/O 操作,让程序在等待 I/O 时释放资源,适合 I/O 密集型任务。适用于串行任务,不提升单次耗时,但是对整个程序来说可以提示吞吐量。
  • 多线程用于让多个任务并行执行,充分利用 CPU 核心资源,适合 CPU 密集型任务。之前的单次任务可以拆分给不同任务执行的话可以提升耗时,通过消耗硬件资源实现并行或者并发提升效率。

标签:异步,Task,C#,任务,线程,多线程,CPU
From: https://www.cnblogs.com/dx5800/p/18527491

相关文章