多线程与优先级调整:用Stopwatch统计线程耗时并找最短耗时线程
线程执行时间统计与最短耗时线程查找方案
嘿,你的思路其实没问题——用Stopwatch来统计线程执行时间是完全可行的,不过我们可以优化一下实现方式,让结果统计和线程管理更清晰。另外你提到C/C++里的GetThreadTimes,.NET里也有对应的方案,我来给你详细梳理下:
完整可运行的实现示例
我们可以把每个线程的计时结果统一存储起来,等所有线程都执行完毕后,再统计找出耗时最短的那个:
using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Diagnostics; class ThreadTimingDemo { // 用来存每个线程的名称和对应的耗时 private static readonly Dictionary<string, TimeSpan> _threadExecutionTimes = new Dictionary<string, TimeSpan>(); private static readonly object _lockObj = new object(); static void Main() { // 创建线程的时候给个名称,后面统计的时候好识别 Thread t1 = new Thread(FirstThread) { Name = "FirstThread" }; Thread t2 = new Thread(SecondThread) { Name = "SecondThread" }; Thread t3 = new Thread(ThirdThread) { Name = "ThirdThread" }; // 启动所有线程 t1.Start(); t2.Start(); t3.Start(); // 必须等所有线程都跑完再统计,不然会拿到不完整的结果 t1.Join(); t2.Join(); t3.Join(); // 先输出所有线程的耗时 Console.WriteLine("各线程执行耗时:"); foreach (var kvp in _threadExecutionTimes) { Console.WriteLine($"{kvp.Key}: {kvp.Value.TotalMilliseconds:F2} ms"); } // 找出耗时最短的线程 var fastestThread = _threadExecutionTimes.OrderBy(kvp => kvp.Value).First(); Console.WriteLine($"\n耗时最短的线程是:{fastestThread.Key},耗时 {fastestThread.Value.TotalMilliseconds:F2} ms"); } static void FirstThread() { Stopwatch stopwatch = Stopwatch.StartNew(); try { // 模拟你的业务逻辑:计算1到10000的和 Enumerable.Range(1, 10000).Select(x => x).Sum(); } finally { stopwatch.Stop(); // 多个线程同时写字典会出问题,所以加个锁保证线程安全 lock (_lockObj) { _threadExecutionTimes[Thread.CurrentThread.Name] = stopwatch.Elapsed; } } } static void SecondThread() { Stopwatch stopwatch = Stopwatch.StartNew(); try { // 模拟另一种业务场景:字符串拼接操作 string result = string.Empty; for (int i = 0; i < 10000; i++) { result += i.ToString(); } } finally { stopwatch.Stop(); lock (_lockObj) { _threadExecutionTimes[Thread.CurrentThread.Name] = stopwatch.Elapsed; } } } static void ThirdThread() { Stopwatch stopwatch = Stopwatch.StartNew(); try { // 模拟IO密集型操作(用Sleep代替实际的IO等待) Thread.Sleep(100); } finally { stopwatch.Stop(); lock (_lockObj) { _threadExecutionTimes[Thread.CurrentThread.Name] = stopwatch.Elapsed; } } } }
几点要注意的地方
- 线程安全的结果存储:因为多个线程会同时往
_threadExecutionTimes字典里写数据,必须用lock来保证线程安全,不然很容易出现并发异常或者数据错乱。 - 等待线程执行完成:一定要用
Thread.Join()等所有线程都跑完再统计结果,不然可能会出现部分线程还在运行,统计结果不完整的情况。 - Stopwatch的优势:
Stopwatch是基于系统高精度计时器实现的,对于测量代码段的执行时间非常精准,完全能满足你的需求。
关于.NET中类似GetThreadTimes的方法
如果你需要获取线程的内核态/用户态CPU时间(就像C/C++里的GetThreadTimes那样),.NET里可以用ProcessThread类来实现:
// 获取当前线程对应的ProcessThread实例 ProcessThread currentThread = Process.GetCurrentProcess().Threads.Cast<ProcessThread>() .First(t => t.Id == Thread.CurrentThread.ManagedThreadId); // 获取线程的用户态CPU时间和内核态CPU时间 TimeSpan userTime = currentThread.UserProcessorTime; TimeSpan kernelTime = currentThread.PrivilegedProcessorTime;
不过要注意,ProcessThread获取的是线程从启动到当前的累计CPU时间,如果你只是想测量特定代码段的执行时间,Stopwatch还是更直接、更合适的选择。
内容的提问来源于stack exchange,提问作者Romazes88
相关产品推荐
相关产品推荐

