文章概述
本文旨在帮助读者理解C#中的异步编程与多线程概念,探讨如何在C#中实现多线程,并对比分析不同实现方法的特点及其适用场景。全文分为两大部分,第一部分介绍异步编程模式async/await
及其与多线程的区别,第二部分则聚焦于C#中实现多线程的三种主要方法:Thread
、ThreadPool
和Task
。
第一部分:异步编程模式 async/await
与多线程的区别
1.1 异步编程模式简介
异步编程模式是一种编程接口设计,主要用于处理并发流程需求。async/await
是C#中实现异步编程的主要方式之一。这种模式允许开发者编写非阻塞代码,提高程序的响应性和效率。
1.2 async/await
使用示例
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# 多线程实现方法
2.1 Thread
类
Thread
类是最基本的多线程实现方式,适用于需要长时间运行的线程。
2.1.1 Thread
使用示例
static void Main(string[] args)
{
Thread thread = new Thread(Fun1);
// Thread thread = new Thread(() => Fun1(0)); // 多线程调用时有参数传递的写法
Console.WriteLine("异步开始");
// thread.IsBackground = true; // 设置为后台线程
thread.Start();
Console.WriteLine("...............按任意键退出");
Console.ReadKey();
}
static void Fun1()
{
var r = Fun2();
var x = Fun3(r);
Console.WriteLine("结果是 {0}", r + x);
}
static int Fun2()
{
Thread.Sleep(1000);
return 100;
}
static int Fun3(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
使用示例
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(testFun), i);
}
Console.WriteLine("主线程结束!");
Console.WriteLine("...............按任意键退出");
Console.ReadKey();
}
public static void testFun(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
使用示例
static void Main(string[] args)
{
Console.WriteLine("主线程执行!");
// 方法一
Task t1 = new Task(() =>
{
Console.WriteLine("方法1的任务开始工作……");
Thread.Sleep(5000);
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 Task
的高级用法
2.4.1 带返回值的 Task
static void Main(string[] args)
{
Console.WriteLine("主线程执行!");
Task<int> task = CreateTask("Task 1");
task.Start();
int result = task.Result;
Console.WriteLine("Task 1 Result is: {0}", result);
Console.WriteLine("主线程结束!");
Console.WriteLine("...............按任意键退出");
Console.ReadKey();
}
static Task<int> CreateTask(string name)
{
return new Task<int>(() => TaskMethod(name));
}
static int TaskMethod(string name)
{
Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
Thread.Sleep(TimeSpan.FromSeconds(2));
return 42;
}
2.4.2 ContinueWith
方法
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
方法
static void Main(string[] args)
{
Console.WriteLine("主线程执行!");
Task t1 = new Task(() =>
{
Console.WriteLine("方法1的任务开始工作……");
Thread.Sleep(5000);
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
,因其灵活性和性能优势。
希望本文能帮助读者更好地理解和应用C#中的异步编程和多线程技术。
参考资料
清华大学出版社《C#从入门到精通(第3版)》 浅析C#中的Thread ThreadPool Task和async/await 谈谈C#的异步和多线程 C#多线程与异步的区别 c#的async到不是不是异步,它和多线程是什么关系 C#线程Thread类 C#多线程--线程池(ThreadPool) C#Task详解
请阅读原文
出处:https://www.cnblogs.com/hellohxs/p/14358776.html
版权申明:本文来源于网友收集或网友提供,如果有侵权,请转告版主或者留言,本公众号立即删除。