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
方法可以返回void
、Task
或Task<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#中常用的多线程实现方式包括Thread
、ThreadPool
和Task
。具体选择哪种方法取决于应用场景:
长时间运行的线程:推荐使用Thread
。
频繁创建和销毁线程且运行时间较短:推荐使用ThreadPool
。
其他一般场景:推荐使用Task
,因其灵活性和性能优势。