C#异步编程与多线程

C#异步编程与多线程

本文来自微信大佬的公众号文章,记录下来,已以备后面复习使用。大佬的公众号是:【DotNet技术匠】,文章链接如下:C# 异步编程与多线程简析:Thread、ThreadPool、Task

那么根据文章内容,我直接复制抄写了一遍哈。

一、异步编程模式async/await与多线程的区别

1.1异步编程模式async/await介绍

异步编程模式是一种编程接口设计,主要用于处理并发流程需求。async/await是C#中实现异步编程的主要方式之一。这种模式允许开发者编写非阻塞代码,提高程序的响应性和效率。

1.2、async/await使用示例

using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AsyncTest
{
    internal class Program
    {
        static void Main(string[] args)
        {
            _ = Async1();
            Console.WriteLine("........按任意键退出");
            Console.ReadKey();
        }

        static async Task Async1()
        {
            Console.WriteLine("异步开始");
            var r = await Async2();
            var x = await Async3(r);
            Console.WriteLine("结果是{0}",r+x);
        }

        static async Task<int> Async2()
        {
           await Task.Delay(1000);
           return 100;
        }

        static async Task<int> Async3(int x)
        {
            await Task.Delay(1000);
            return x % 7;
        }

    }
}

程序运行结果:

在这里插入图片描述

通过上述代码可以看到,async关键字修饰的方法为异步方法,而await关键字用于标记异步操作的开始点。只有当两者配合使用时,方法才会真正实现异步执行。

1.3、async/await 的特点

异步执行:在遇到await关键字时,方法会暂停执行,不会阻塞当前线程,而是允许其他任务继续运行。

代码可读性:虽然async/await提高了代码的并发能力,但在某些情况下,可能会降低代码的可读性。

返回值类型async方法可以返回voidTaskTask<T>

二、C#中实现多线程的3种方法

2.1 Thread类

Thread类是最基本的多线程实现方式,适用于需要长时间运行的线程。

2.1.1 Thread类的使用示例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ThreadTest
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Thread thread = new Thread(Func1);

            Console.WriteLine("异步开始");

            thread.Start();

            Console.WriteLine("........按任意键退出");
            Console.ReadKey();
        }

        public static void Func1()
        {
            var r = Func2();
            var x = Func3(r);
            Console.WriteLine("结果是{0}", r + x);
        }

        public static int Func2()
        {
            Thread.Sleep(1000);
            return 100;
        }

        public static int Func3(int x)
        {
            Thread.Sleep(1000);
            return x % 7;
        }
    }
}

程序运行结果:

在这里插入图片描述

2.1.2、Thread 的特点

内存消耗:每次创建新的Thread对象都会消耗一定的内存(约1MB)。

线程类型:默认为前台线程,可以通过IsBackground属性设置为后台线程。

参数传递:可以通过Start方法传递参数,但参数类型必须为object

2.2 ThreadPool 线程池

ThreadPool适用于需要频繁创建和销毁线程且每个线程运行时间较短的场景。

2.2.1 ThreadPool 线程池使用示例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ThreadPoolTest
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("主线程执行");
            ThreadPool.SetMinThreads(1,1);
            ThreadPool.SetMaxThreads(5,5);

            for (int i=1;i <= 10;i++)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(TestFunc),i);
            }

            Console.WriteLine("主线程结束");

            Console.WriteLine("........按任意键退出");
            Console.ReadKey();
        }

        public static void TestFunc(object obj)
        {
            Console.WriteLine(string.Format("{0}:第{1}个线程"),DateTime.Now.ToString(),
                obj.ToString());
            Thread.Sleep(5000);
        }
    }
}

程序运行结果:

在这里插入图片描述

2.2.2、ThreadPool的特点

线程池特性:线程池是一个静态类,通过QueueUserWorkItem方法将工作项加入线程池。

性能优势:避免了频繁创建和销毁线程的开销,提高了程序性能。

线程管理:无法直接控制线程的开始、挂起和终止。

2.3 Task类

Task类是C#中推荐的多线程实现方式,适用于大多数场景。

2.3.1、Task使用示例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace TaskTest
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("主线程执行!");

            // 方法一
            Task t1 = new Task(()=>
            {
                Console.WriteLine("方法1的任务开始执行");
                Thread.Sleep(2000);
                Console.WriteLine("方法1的任务执行完成");
            });
            t1.Start();

            // 方法二
            Task.Run(() =>
            {
                Console.WriteLine("方法2的任务开始执行");
                Thread.Sleep(5000);
                Console.WriteLine("方法2的任务执行完成");
            });

            // 方法三
            var t3 = Task.Factory.StartNew(() =>
            {
                Console.WriteLine("方法3的任务开始执行");
                Thread.Sleep(5000);
                Console.WriteLine("方法3的任务执行完成");
            });

            Console.WriteLine("主线程结束执行!");

            Console.WriteLine("........按任意键退出");
            Console.ReadKey();
        }
    }
}

程序运行结果:

在这里插入图片描述

2.3.2 Task 的特点

灵活性:提供了丰富的API,支持多种管理和控制方法。

性能优化:使用本地队列减少线程之间的资源竞争。

返回值:可以通过Task<T>获取任务的返回值。

2.4 Tas高级用法

2.4.1、带返回值的 Task
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Runtime.CompilerServices;

namespace TaskAdvTest
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("主线程执行");
            Task<int> task = CreateTask("Task 1");
            task.Start();
            int nResult = task.Result;
            Console.WriteLine("Task 1 Result is {0}", nResult);

            Console.WriteLine("主线程结束执行");
            Console.WriteLine("........按任意键退出");
            Console.ReadKey();
        }

        public static Task<int> CreateTask(string strName)
        {
            return new Task<int>(() => TaskMethod(strName));
        }

        public static int TaskMethod(string strName)
        { 
            Console.WriteLine("Thread {0} is Runing On a Thread ID {1},Is Thread pool thread:{2}"
                , strName,Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
            Thread.Sleep(TimeSpan.FromSeconds(2));
            return 42;
        }
    }
}

程序运行结果:

在这里插入图片描述

2.4.2、ContinueWith方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TaskAdvTest2
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("主线程执行");
            Task t1 = new Task(() =>
            {
                Console.WriteLine("方法1的任务开始执行");
                Thread.Sleep(5000);
                Console.WriteLine("方法1的任务结束执行");
            });
            t1.Start();
            t1.ContinueWith( t => Console.WriteLine("方法1的任务继续执行")); 

            Console.WriteLine("主线程结束执行");
            Console.WriteLine("........按任意键退出");
            Console.ReadKey();
        }
    }
}

在这里插入图片描述

2.4.3、Task.WaitAll方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TaskAdvTest3
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("主线程执行!");

            // 方法一
            Task t1 = new Task(() =>
            {
                Console.WriteLine("方法1的任务开始执行");
                Thread.Sleep(2000);
                Console.WriteLine("方法1的任务执行完成");
            });
            t1.Start();

            // 方法二
            Task t2 = new Task(() =>
            {
                Console.WriteLine("方法2的任务开始执行");
                Thread.Sleep(5000);
                Console.WriteLine("方法2的任务执行完成");
            });
            t2.Start();

            Task.WaitAll(t1,t2);

            Console.WriteLine("主线程结束执行!");
            Console.WriteLine("........按任意键退出");
            Console.ReadKey();
        }
    }
}

程序运行结果:

在这里插入图片描述

总结

多线程是实现异步的一种方法,C#中常用的多线程实现方式包括ThreadThreadPoolTask。具体选择哪种方法取决于应用场景:

长时间运行的线程:推荐使用Thread

频繁创建和销毁线程且运行时间较短:推荐使用ThreadPool

其他一般场景:推荐使用Task,因其灵活性和性能优势。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值