c# 线程和进程的区别

来源:这里教程网 时间:2026-02-21 17:41:36 作者:

进程是操作系统分配资源的基本单位

一个

Process
对应一个独立的内存空间、句柄表和安全上下文。你启动一个
dotnet MyApp.dll
,系统就创建一个新进程;再开一个,就是另一个完全隔离的进程。它们之间默认不共享内存,通信得靠
NamedPipe
MemoryMappedFile
WCF
这类跨进程机制。

常见误区是以为“多开几个控制台窗口跑同一个程序,它们能互相改对方的变量”——不能。每个窗口背后是独立

Process
static
字段也互不影响。

线程是进程内执行代码的最小调度单元

同一进程里的多个

Thread
(或
Task
)共享堆内存、全局变量和文件句柄。比如你在
Main
方法里声明一个
static List<int> shared = new();</int>
,所有线程都能读写它——但这也意味着必须手动加锁(
lock
Monitor
ConcurrentQueue
),否则容易出现数据错乱。

注意:.NET 中推荐用

Task
而不是裸
Thread
,因为
ThreadPool
会复用线程,避免频繁创建销毁的开销。直接 new
Thread
只在需要长时间独占、设置特定优先级或避免被线程池回收时才用。

Thread
启动开销大,
Task.Run
更轻量
UI 线程(如 WinForms/WPF 的主线程)不能被
Thread.Sleep
阻塞,否则界面冻结;要用
await Task.Delay
async/await
不一定新建线程,它只是释放当前线程去干别的事,回调时可能回到原线程(尤其 UI 上下文)

看任务管理器就能直观区分

打开 Windows 任务管理器 → “详细信息”页,每一行是一个

Process
(比如
devenv.exe
chrome.exe
)。右键 → “转到服务”或“转到进程”,能看到它下面挂了多少个线程(列名是 “线程数”)。这个数字是该进程内所有线程的总和,包括主线程、GC 线程、ThreadPool 线程、Timer 回调线程等。

如果你用

Process.GetCurrentProcess().Threads.Count
,拿到的就是当前进程的线程总数,不是你代码里显式
new Thread()
的个数。

什么时候该用进程,什么时候该用线程

选进程:需要强隔离(比如插件沙箱、用户代码执行)、崩溃不能影响主程序、或必须加载不同版本的同一 DLL(如两个插件依赖不同版

Newtonsoft.Json
)。

选线程(或

Task
):同一业务逻辑并行处理(如批量下载、图像处理)、响应式 UI、I/O 等待期间不阻塞主线程。

特别注意:

AppDomain
在 .NET Core/.NET 5+ 已被移除,不能再靠它做隔离——现在只有进程级隔离最可靠。

var p = Process.Start("notepad.exe");
Console.WriteLine($"新进程 ID: {p.Id}");
// 此时 notepad 和当前程序完全无关,杀掉它也不会影响本程序

线程间共享内存是双刃剑:快,但也容易出竞态。别指望“我只读不写”就绝对安全——没有

volatile
或内存屏障,CPU 可能缓存旧值;没加锁的写操作也可能被重排序。真要共享,优先选
ConcurrentDictionary
这类线程安全集合,而不是自己上
lock

相关推荐