商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > c#如何实现多线程_c#多线程的正确用法与注意事项

c#如何实现多线程_c#多线程的正确用法与注意事项

  发布于2026-07-18 阅读(0)

扫一扫,手机访问

在C#里处理多线程,最核心的转变就是把目光从Thread转向Task。直接new Thread启动线程,老实说,已经有点跟不上时代了。.NET 4.0+ 的推荐做法,是使用Task,它由线程池调度,支持async/await,异常能被自然捕获,也省去了手动管理生命周期的麻烦。

c#如何实现多线程_c#多线程的正确用法与注意事项

Task 而不是 Thread 启动并发操作

直接在UI线程里写new Thread(() => { /* 耗时操作 */ }).Start(),这其实是个常见坑。不仅没法用await等待,异常还会偷偷丢失,搞不好UI就卡死了。正确的做法是var task = Task.Run(() => DoHea vyWork());,后续可以await task或者task.Wait()

如果并发数需要控制,比如最多只允许4个任务同时跑,那就用SemaphoreSlimTask.Run包起来。至于Task.Factory.StartNew,它虽然提供了更多重载参数(比如CancellationToken、调度选项),但多数场景下Task.Run更安全,语义也更清晰。

共享变量必须加锁或换用线程安全类型

多个Task同时读写同一个intList或者自定义对象字段,不出错真的只能靠运气。竞态条件(race condition)的后果很严重:值突变、索引越界、数据丢失,而且极难复现。典型的例子是,counter++在10个任务中各执行1000次,结果counter竟然小于10000;或者list.Add(x)直接抛出InvalidOperationException

处理方案其实很明确:简单计数器优先用Interlocked.Increment(ref counter),比lock开销更低。集合类则改用ConcurrentQueueConcurrentDictionary,它们内部已经做了细粒度同步。真要写lock,确保锁对象是私有静态或实例的readonly字段,千万别用lock(this)lock(typeof(X)),很容易引发死锁或意外干扰。

async/await 不等于多线程,别误以为写了 await 就自动并行

这一点得特别强调:await的本质是“让出当前线程,等I/O完成后继续”,它本身并不创建新线程。很多开发者会误以为await Task.Delay(1000)await httpClient.GetAsync(url)会占用线程池线程,实际上它们几乎不消耗CPU,底层靠操作系统的I/O完成端口(Windows)或epoll/kqueue(Linux/macOS)驱动。

一个典型的错误用法是await Task.Run(() => Thread.Sleep(1000)),这纯粹是在浪费线程池资源,应该直接用await Task.Delay(1000)。区分清楚场景很重要:I/O密集型操作(HTTP请求、文件读写、数据库查询)优先用原生异步方法,比如ReadAsyncExecuteScalarAsync,它们才是真正的异步。CPU密集型操作(图像处理、加密计算)才需要Task.Run搬到后台线程,但注意别无节制地启动几十个,会拖垮线程池。如果想真正并行执行多个异步操作,用Task.WhenAll(task1, task2, task3),而不是串行写三个await

别忽略 CancellationToken 和异常传播

一个没被取消的长时间运行任务,可能让整个应用无法退出;一个未被处理的Task异常,会在GC时触发UnobservedTaskException事件(.NET 6+ 默认终止进程)。常见疏漏是调用Task.Run后只await却不检查IsFaulted,或者根本没传CancellationToken给耗时方法。

正确的做法是:所有可取消的长时间操作,接口都应接受CancellationToken参数,并在内部定期调用token.ThrowIfCancellationRequested()await一个可能失败的Task,异常会原样抛出;但如果用.Wait().Result,异常会被包进AggregateException,需要遍历.InnerExceptions。另外,如果任务已经开始但中途需要放弃,务必确保资源(如文件句柄、数据库连接)能被正确释放——using + try/finallyawait using是底线。

说到底,多线程真正的复杂点不在语法,而在状态共享的边界是否清晰、取消是否及时响应、异常是否总被看见。哪怕只加一行lock或一个CancellationToken,漏掉就可能让问题延后几小时甚至几天才暴露。

本文转载于:https://www.php.cn/faq/2343891.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注