学习目标
通过本章学习,你将掌握:
- 性能分析和诊断工具的使用
- 内存管理和垃圾回收优化
- 异步编程性能优化
- 数据库查询优化
- 缓存策略和实现
- 调试技术和工具
- 性能监控和分析
21.1 性能分析和诊断
性能分析工具
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Linq;
using System.IO;
using System.Text.Json;
// 性能分析器
public class PerformanceAnalyzer
{
private readonly List<PerformanceMetric> _metrics;
private readonly Dictionary<string, Stopwatch> _activeTimers;
public PerformanceAnalyzer()
{
_metrics = new List<PerformanceMetric>();
_activeTimers = new Dictionary<string, Stopwatch>();
}
public void StartTimer(string operationName)
{
if (_activeTimers.ContainsKey(operationName))
{
_activeTimers[operationName].Restart();
}
else
{
_activeTimers[operationName] = Stopwatch.StartNew();
}
}
public TimeSpan StopTimer(string operationName)
{
if (_activeTimers.TryGetValue(operationName, out var stopwatch))
{
stopwatch.Stop();
var elapsed = stopwatch.Elapsed;
_metrics.Add(new PerformanceMetric
{
OperationName = operationName,
Duration = elapsed,
Timestamp = DateTime.UtcNow,
MemoryBefore = GC.GetTotalMemory(false),
MemoryAfter = GC.GetTotalMemory(false)
});
_activeTimers.Remove(operationName);
return elapsed;
}
return TimeSpan.Zero;
}
public T MeasureOperation<T>(string operationName, Func<T> operation)
{
var memoryBefore = GC.GetTotalMemory(false);
var stopwatch = Stopwatch.StartNew();
try
{
var result = operation();
stopwatch.Stop();
var memoryAfter = GC.GetTotalMemory(false);
_metrics.Add(new PerformanceMetric
{
OperationName = operationName,
Duration = stopwatch.Elapsed,
Timestamp = DateTime.UtcNow,
MemoryBefore = memoryBefore,
MemoryAfter = memoryAfter,
MemoryAllocated = memoryAfter - memoryBefore,
Success = true
});
return result;
}
catch (Exception ex)
{
stopwatch.Stop();
_metrics.Add(new PerformanceMetric
{
OperationName = operationName,
Duration = stopwatch.Elapsed,
Timestamp = DateTime.UtcNow,
MemoryBefore = memoryBefore,
MemoryAfter = GC.GetTotalMemory(false),
Success = false,
ErrorMessage = ex.Message
});
throw;
}
}
public async Task<T> MeasureOperationAsync<T>(string operationName, Func<Task<T>> operation)
{
var memoryBefore = GC.GetTotalMemory(false);
var stopwatch = Stopwatch.StartNew();
try
{
var result = await operation();
stopwatch.Stop();
var memoryAfter = GC.GetTotalMemory(false);
_metrics.Add(new PerformanceMetric
{
OperationName = operationName,
Duration = stopwatch.Elapsed,
Timestamp = DateTime.UtcNow,
MemoryBefore = memoryBefore,
MemoryAfter = memoryAfter,
MemoryAllocated = memoryAfter - memoryBefore,
Success = true
});
return result;
}
catch (Exception ex)
{
stopwatch.Stop();
_metrics.Add(new PerformanceMetric
{
OperationName = operationName,
Duration = stopwatch.Elapsed,
Timestamp = DateTime.UtcNow,
MemoryBefore = memoryBefore,
MemoryAfter = GC.GetTotalMemory(false),
Success = false,
ErrorMessage = ex.Message
});
throw;
}
}
public PerformanceReport GenerateReport()
{
var report = new PerformanceReport
{
GeneratedAt = DateTime.UtcNow,
TotalOperations = _metrics.Count,
SuccessfulOperations = _metrics.Count(m => m.Success),
FailedOperations = _metrics.Count(m => !m.Success)
};
if (_metrics.Any())
{
report.AverageExecutionTime = TimeSpan.FromMilliseconds(
_metrics.Average(m => m.Duration.TotalMilliseconds));
report.MaxExecutionTime = _metrics.Max(m => m.Duration);
report.MinExecutionTime = _metrics.Min(m => m.Duration);
report.TotalMemoryAllocated = _metrics.Sum(m => m.MemoryAllocated);
// 按操作分组统计
report.OperationStatistics = _metrics
.GroupBy(m => m.OperationName)
.Select(g => new OperationStatistics
{
OperationName = g.Key,
Count = g.Count(),
AverageExecutionTime = TimeSpan.FromMilliseconds(
g.Average(m => m.Duration.TotalMilliseconds)),
MaxExecutionTime = g.Max(m => m.Duration),
MinExecutionTime = g.Min(m => m.Duration),
TotalMemoryAllocated = g.Sum(m => m.MemoryAllocated),
SuccessRate = (double)g.Count(m => m.Success) / g.Count() * 100
})
.OrderByDescending(s => s.AverageExecutionTime)
.ToList();
// 性能瓶颈识别
report.PerformanceBottlenecks = IdentifyBottlenecks();
}
return report;
}
private List<PerformanceBottleneck> IdentifyBottlenecks()
{
var bottlenecks = new List<PerformanceBottleneck>();
// 识别执行时间异常的操作
var avgExecutionTime = _metrics.Average(m => m.Duration.TotalMilliseconds);
var threshold = avgExecutionTime * 2; // 超过平均值2倍认为是瓶颈
var slowOperations = _metrics
.Where(m => m.Duration.TotalMilliseconds > threshold)
.GroupBy(m => m.OperationName)
.Where(g => g.Count() > 1) // 至少出现2次
.Select(g => new PerformanceBottleneck
{
Type = BottleneckType.SlowExecution,
OperationName = g.Key,
Description = $"Operation '{g.Key}' consistently takes longer than average",
AverageExecutionTime = TimeSpan.FromMilliseconds(
g.Average(m => m.Duration.TotalMilliseconds)),
Occurrences = g.Count(),
Severity = g.Average(m => m.Duration.TotalMilliseconds) > threshold * 2 ?
BottleneckSeverity.High : BottleneckSeverity.Medium
});
bottlenecks.AddRange(slowOperations);
// 识别内存分配异常的操作
var avgMemoryAllocation = _metrics.Average(m => m.MemoryAllocated);
var memoryThreshold = avgMemoryAllocation * 3; // 超过平均值3倍认为是内存瓶颈
var memoryIntensiveOperations = _metrics
.Where(m => m.MemoryAllocated > memoryThreshold)
.GroupBy(m => m.OperationName)
.Select(g => new PerformanceBottleneck
{
Type = BottleneckType.HighMemoryUsage,
OperationName = g.Key,
Description = $"Operation '{g.Key}' allocates excessive memory",
AverageMemoryAllocation = g.Average(m => m.MemoryAllocated),
Occurrences = g.Count(),
Severity = g.Average(m => m.MemoryAllocated) > memoryThreshold * 2 ?
BottleneckSeverity.High : BottleneckSeverity.Medium
});
bottlenecks.AddRange(memoryIntensiveOperations);
return bottlenecks.OrderByDescending(b => b.Severity).ToList();
}
public void ExportMetrics(string filePath)
{
var json = JsonSerializer.Serialize(_metrics, new JsonSerializerOptions
{
WriteIndented = true
});
File.WriteAllText(filePath, json);
}
public void ClearMetrics()
{
_metrics.Clear();
}
}
// CPU和内存分析器
public class SystemResourceAnalyzer
{
private readonly PerformanceCounter _cpuCounter;
private readonly PerformanceCounter _memoryCounter;
private readonly Process _currentProcess;
public SystemResourceAnalyzer()
{
_cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
_memoryCounter = new PerformanceCounter("Memory", "Available MBytes");
_currentProcess = Process.GetCurrentProcess();
}
public SystemResourceSnapshot TakeSnapshot()
{
// 第一次调用CPU计数器需要等待
_cpuCounter.NextValue();
System.Threading.Thread.Sleep(100);
return new SystemResourceSnapshot
{
Timestamp = DateTime.UtcNow,
CpuUsagePercent = _cpuCounter.NextValue(),
AvailableMemoryMB = _memoryCounter.NextValue(),
ProcessMemoryMB = _currentProcess.WorkingSet64 / 1024 / 1024,
ProcessPrivateMemoryMB = _currentProcess.PrivateMemorySize64 / 1024 / 1024,
ProcessVirtualMemoryMB = _currentProcess.VirtualMemorySize64 / 1024 / 1024,
ThreadCount = _currentProcess.Threads.Count,
HandleCount = _currentProcess.HandleCount,
GCTotalMemory = GC.GetTotalMemory(false),
GCGen0Collections = GC.CollectionCount(0),
GCGen1Collections = GC.CollectionCount(1),
GCGen2Collections = GC.CollectionCount(2)
};
}
public async Task<List<SystemResourceSnapshot>> MonitorAsync(
TimeSpan duration, TimeSpan interval)
{
var snapshots = new List<SystemResourceSnapshot>();
var endTime = DateTime.UtcNow.Add(duration);
while (DateTime.UtcNow < endTime)
{
snapshots.Add(TakeSnapshot());
await Task.Delay(interval);
}
return snapshots;
}
public ResourceAnalysisReport AnalyzeSnapshots(List<SystemResourceSnapshot> snapshots)
{
if (!snapshots.Any())
return new ResourceAnalysisReport();
return new ResourceAnalysisReport
{
AnalyzedAt = DateTime.UtcNow,
Duration = snapshots.Last().Timestamp - snapshots.First().Timestamp,
SnapshotCount = snapshots.Count,
// CPU分析
AverageCpuUsage = snapshots.Average(s => s.CpuUsagePercent),
MaxCpuUsage = snapshots.Max(s => s.CpuUsagePercent),
MinCpuUsage = snapshots.Min(s => s.CpuUsagePercent),
// 内存分析
AverageProcessMemory = snapshots.Average(s => s.ProcessMemoryMB),
MaxProcessMemory = snapshots.Max(s => s.ProcessMemoryMB),
MinProcessMemory = snapshots.Min(s => s.ProcessMemoryMB),
MemoryGrowth = snapshots.Last().ProcessMemoryMB - snapshots.First().ProcessMemoryMB,
// GC分析
TotalGCGen0Collections = snapshots.Last().GCGen0Collections - snapshots.First().GCGen0Collections,
TotalGCGen1Collections = snapshots.Last().GCGen1Collections - snapshots.First().GCGen1Collections,
TotalGCGen2Collections = snapshots.Last().GCGen2Collections - snapshots.First().GCGen2Collections,
// 线程分析
AverageThreadCount = snapshots.Average(s => s.ThreadCount),
MaxThreadCount = snapshots.Max(s => s.ThreadCount),
MinThreadCount = snapshots.Min(s => s.ThreadCount),
// 资源警告
ResourceWarnings = GenerateResourceWarnings(snapshots)
};
}
private List<ResourceWarning> GenerateResourceWarnings(List<SystemResourceSnapshot> snapshots)
{
var warnings = new List<ResourceWarning>();
// CPU使用率警告
var highCpuSnapshots = snapshots.Where(s => s.CpuUsagePercent > 80).ToList();
if (highCpuSnapshots.Count > snapshots.Count * 0.1) // 超过10%的时间CPU使用率过高
{
warnings.Add(new ResourceWarning
{
Type = ResourceWarningType.HighCpuUsage,
Severity = highCpuSnapshots.Any(s => s.CpuUsagePercent > 95) ?
WarningSeverity.Critical : WarningSeverity.Warning,
Description = $"CPU usage exceeded 80% for {highCpuSnapshots.Count} out of {snapshots.Count} measurements",
MaxValue = highCpuSnapshots.Max(s => s.CpuUsagePercent)
});
}
// 内存增长警告
var memoryGrowth = snapshots.Last().ProcessMemoryMB - snapshots.First().ProcessMemoryMB;
if (memoryGrowth > 100) // 内存增长超过100MB
{
warnings.Add(new ResourceWarning
{
Type = ResourceWarningType.MemoryLeak,
Severity = memoryGrowth > 500 ? WarningSeverity.Critical : WarningSeverity.Warning,
Description = $"Process memory increased by {memoryGrowth:F2} MB during monitoring period",
MaxValue = memoryGrowth
});
}
// GC频率警告
var duration = snapshots.Last().Timestamp - snapshots.First().Timestamp;
var gen2CollectionsPerMinute = (snapshots.Last().GCGen2Collections - snapshots.First().GCGen2Collections) /
duration.TotalMinutes;
if (gen2CollectionsPerMinute > 1) // Gen2 GC每分钟超过1次
{
warnings.Add(new ResourceWarning
{
Type = ResourceWarningType.FrequentGC,
Severity = gen2CollectionsPerMinute > 5 ? WarningSeverity.Critical : WarningSeverity.Warning,
Description = $"Generation 2 GC occurring {gen2CollectionsPerMinute:F2} times per minute",
MaxValue = gen2CollectionsPerMinute
});
}
return warnings;
}
public void Dispose()
{
_cpuCounter?.Dispose();
_memoryCounter?.Dispose();
_currentProcess?.Dispose();
}
}
// 数据库查询相关数据模型
public class QueryPerformanceMetric
{
public string QueryName { get; set; }
public string Sql { get; set; }
public string Parameters { get; set; }
public TimeSpan ExecutionTime { get; set; }
public DateTime StartTime { get; set; }
public bool Success { get; set; }
public string ErrorMessage { get; set; }
public int RowsAffected { get; set; }
}
public class QueryPerformanceReport
{
public DateTime GeneratedAt { get; set; }
public int TotalQueries { get; set; }
public int SuccessfulQueries { get; set; }
public int FailedQueries { get; set; }
public TimeSpan AverageExecutionTime { get; set; }
public TimeSpan MaxExecutionTime { get; set; }
public TimeSpan MinExecutionTime { get; set; }
public List<QueryPerformanceMetric> SlowQueries { get; set; }
public List<QueryStatistics> QueryStatistics { get; set; }
public List<PerformanceRecommendation> PerformanceRecommendations { get; set; }
}
public class QueryStatistics
{
public string QueryName { get; set; }
public int ExecutionCount { get; set; }
public TimeSpan AverageExecutionTime { get; set; }
public TimeSpan MaxExecutionTime { get; set; }
public TimeSpan MinExecutionTime { get; set; }
public double SuccessRate { get; set; }
public int TotalRowsAffected { get; set; }
}
public class PerformanceRecommendation
{
public RecommendationType Type { get; set; }
public string QueryName { get; set; }
public string Description { get; set; }
public string Suggestion { get; set; }
public RecommendationPriority Priority { get; set; }
}
public enum RecommendationType
{
NPlusOneQuery,
MissingIndex,
LargeResultSet,
UnoptimizedJoin,
RedundantQuery
}
public enum RecommendationPriority
{
Low,
Medium,
High,
Critical
}
public class QueryOptimizationOptions
{
public bool AsNoTracking { get; set; } = true;
public bool SplitQuery { get; set; } = false;
public TimeSpan? CommandTimeout { get; set; }
}
public class QueryExecutionPlan
{
public string Sql { get; set; }
public TimeSpan ExecutionTime { get; set; }
public int RowCount { get; set; }
public DateTime AnalyzedAt { get; set; }
}
public class ConnectionPoolStats
{
public DateTime Timestamp { get; set; }
public long ActiveConnections { get; set; }
public long ConnectionsPerSecond { get; set; }
public long DisconnectionsPerSecond { get; set; }
public TimeSpan ConnectionEstablishmentTime { get; set; }
public bool IsHealthy { get; set; }
public string ErrorMessage { get; set; }
}
// User 实体类(示例)
public class User
{
public int Id { get; set; }
public string Email { get; set; }
public int Age { get; set; }
public string Name { get; set; }
}
// 缓存相关数据模型
public class CacheConfiguration
{
public CacheOptions DefaultOptions { get; set; } = new CacheOptions();
public int MaxMemoryCacheSize { get; set; } = 100;
public TimeSpan CleanupInterval { get; set; } = TimeSpan.FromMinutes(5);
}
public class CacheOptions
{
public TimeSpan MemoryExpiration { get; set; } = TimeSpan.FromMinutes(10);
public TimeSpan DistributedExpiration { get; set; } = TimeSpan.FromHours(1);
public CachePriority Priority { get; set; } = CachePriority.Normal;
}
public enum CachePriority
{
Low,
Normal,
High,
NeverRemove
}
public enum CacheLevel
{
Memory,
Distributed
}
public class CacheMetrics
{
private long _memoryHits;
private long _distributedHits;
private long _misses;
private readonly object _lock = new object();
public void RecordHit(CacheLevel level)
{
lock (_lock)
{
if (level == CacheLevel.Memory)
_memoryHits++;
else
_distributedHits++;
}
}
public void RecordMiss()
{
lock (_lock)
{
_misses++;
}
}
public CacheMetricsReport GenerateReport()
{
lock (_lock)
{
var total = _memoryHits + _distributedHits + _misses;
return new CacheMetricsReport
{
MemoryHits = _memoryHits,
DistributedHits = _distributedHits,
Misses = _misses,
TotalRequests = total,
HitRate = total > 0 ? (double)(_memoryHits + _distributedHits) / total : 0,
MemoryHitRate = total > 0 ? (double)_memoryHits / total : 0
};
}
}
}
public class CacheMetricsReport
{
public long MemoryHits { get; set; }
public long DistributedHits { get; set; }
public long Misses { get; set; }
public long TotalRequests { get; set; }
public double HitRate { get; set; }
public double MemoryHitRate { get; set; }
}
public class CacheWarmupTask
{
public string Key { get; set; }
public Func<Task<object>> Factory { get; set; }
public CacheOptions Options { get; set; }
}
public class CacheAccessPattern
{
public string Key { get; set; }
public int AccessCount { get; set; }
public DateTime FirstAccess { get; set; } = DateTime.UtcNow;
public DateTime LastAccess { get; set; }
}
// 调试相关数据模型
public class DebugEvent
{
public DebugEventType Type { get; set; }
public DateTime Timestamp { get; set; }
public string MethodName { get; set; }
public string FilePath { get; set; }
public int LineNumber { get; set; }
public string[] Parameters { get; set; }
public string ReturnValue { get; set; }
public Exception Exception { get; set; }
public string VariableName { get; set; }
public string VariableValue { get; set; }
public int ThreadId { get; set; }
public string StackTrace { get; set; }
}
public enum DebugEventType
{
MethodEntry,
MethodExit,
Exception,
VariableState
}
public class DebugReport
{
public DateTime GeneratedAt { get; set; }
public TimeSpan? TimeRange { get; set; }
public int TotalEvents { get; set; }
public List<DebugEvent> Events { get; set; }
public List<ExceptionSummary> ExceptionSummary { get; set; }
public List<MethodCallSummary> MethodCallSummary { get; set; }
public ThreadAnalysis ThreadAnalysis { get; set; }
}
public class ExceptionSummary
{
public string ExceptionType { get; set; }
public int Count { get; set; }
public DateTime LastOccurrence { get; set; }
public List<string> CommonMethods { get; set; }
}
public class MethodCallSummary
{
public string MethodName { get; set; }
public int CallCount { get; set; }
public TimeSpan AverageExecutionTime { get; set; }
public DateTime LastCalled { get; set; }
}
public class ThreadAnalysis
{
public int TotalThreads { get; set; }
public List<ThreadDetail> ThreadDetails { get; set; }
}
public class ThreadDetail
{
public int ThreadId { get; set; }
public int EventCount { get; set; }
public DateTime FirstActivity { get; set; }
public DateTime LastActivity { get; set; }
public int ExceptionCount { get; set; }
}
public class MethodPerformanceData
{
public string MethodName { get; set; }
public int CallCount { get; set; }
public TimeSpan TotalDuration { get; set; }
public TimeSpan MinDuration { get; set; }
public TimeSpan MaxDuration { get; set; }
public long TotalMemoryDelta { get; set; }
public int SuccessCount { get; set; }
public TimeSpan AverageDuration => CallCount > 0 ?
TimeSpan.FromTicks(TotalDuration.Ticks / CallCount) : TimeSpan.Zero;
public long AverageMemoryDelta => CallCount > 0 ? TotalMemoryDelta / CallCount : 0;
public double SuccessRate => CallCount > 0 ? (double)SuccessCount / CallCount : 0;
public double ErrorRate => 1 - SuccessRate;
}
public class PerformanceProfileReport
{
public DateTime GeneratedAt { get; set; }
public int TotalMethods { get; set; }
public List<MethodPerformanceData> MethodPerformanceData { get; set; }
public List<MethodPerformanceData> TopSlowMethods { get; set; }
public List<MethodPerformanceData> TopMemoryConsumers { get; set; }
public List<MethodPerformanceData> MethodsWithErrors { get; set; }
}
// 性能监控相关数据模型
public class PerformanceSnapshot
{
public DateTime Timestamp { get; set; }
public double CpuUsage { get; set; }
public double MemoryUsage { get; set; }
public int GcCollections { get; set; }
public int ThreadCount { get; set; }
public int HandleCount { get; set; }
public double RequestsPerSecond { get; set; }
public double AverageResponseTime { get; set; }
}
public class PerformanceAlert
{
public AlertType Type { get; set; }
public AlertSeverity Severity { get; set; }
public string Message { get; set; }
public DateTime Timestamp { get; set; }
public double Value { get; set; }
}
public enum AlertType
{
HighCpuUsage,
HighMemoryUsage,
SlowResponse,
HighGcPressure,
LowThroughput,
HighErrorRate
}
public enum AlertSeverity
{
Info,
Warning,
Critical
}
public class PerformanceAnalysisReport
{
public DateTime GeneratedAt { get; set; }
public TimeSpan TimeRange { get; set; }
public int SnapshotCount { get; set; }
public string Message { get; set; }
public MetricAnalysis CpuAnalysis { get; set; }
public MetricAnalysis MemoryAnalysis { get; set; }
public MetricAnalysis ResponseTimeAnalysis { get; set; }
public MetricAnalysis ThroughputAnalysis { get; set; }
public List<TrendAnalysis> Trends { get; set; }
public List<PerformanceRecommendation> Recommendations { get; set; }
}
public class MetricAnalysis
{
public double Average { get; set; }
public double Minimum { get; set; }
public double Maximum { get; set; }
public double StandardDeviation { get; set; }
public double Percentile95 { get; set; }
public double Percentile99 { get; set; }
}
public class TrendAnalysis
{
public string Metric { get; set; }
public TrendDirection Direction { get; set; }
public double Slope { get; set; }
public double Confidence { get; set; }
}
public enum TrendDirection
{
Increasing,
Decreasing,
Stable
}
public class PerformanceRecommendation
{
public RecommendationType Type { get; set; }
public RecommendationPriority Priority { get; set; }
public string Description { get; set; }
public string Suggestion { get; set; }
}
public enum RecommendationType
{
CpuOptimization,
MemoryOptimization,
ResponseTimeOptimization,
ThroughputOptimization,
GcOptimization
}
public enum RecommendationPriority
{
Low,
Medium,
High
}
public class RequestMetric
{
public DateTime Timestamp { get; set; }
public TimeSpan ResponseTime { get; set; }
}
// 实践练习相关数据模型
public class PerformanceTest
{
public string Name { get; set; }
public Func<Task> TestAction { get; set; }
public int Iterations { get; set; }
}
public class ComprehensivePerformanceReport
{
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public TimeSpan TotalDuration { get; set; }
public List<PerformanceTestResult> TestResults { get; set; }
public PerformanceSummary Summary { get; set; }
}
public class PerformanceTestResult
{
public string TestName { get; set; }
public int Iterations { get; set; }
public int SuccessfulIterations { get; set; }
public int FailedIterations { get; set; }
public List<TimeSpan> ExecutionTimes { get; set; } = new List<TimeSpan>();
public List<MemorySnapshot> MemorySnapshots { get; set; } = new List<MemorySnapshot>();
public List<string> Errors { get; set; } = new List<string>();
// 统计信息
public TimeSpan MinExecutionTime { get; set; }
public TimeSpan MaxExecutionTime { get; set; }
public TimeSpan AverageExecutionTime { get; set; }
public TimeSpan MedianExecutionTime { get; set; }
public TimeSpan Percentile95 { get; set; }
public TimeSpan Percentile99 { get; set; }
public long TotalMemoryAllocated { get; set; }
public long AverageMemoryPerIteration { get; set; }
public double ThroughputPerSecond { get; set; }
}
public class MemorySnapshot
{
public int Iteration { get; set; }
public long MemoryBefore { get; set; }
public long MemoryAfter { get; set; }
public long MemoryDelta { get; set; }
}
public class PerformanceSummary
{
public int TotalTests { get; set; }
public int TotalIterations { get; set; }
public int TotalSuccessfulIterations { get; set; }
public int TotalFailedIterations { get; set; }
public TimeSpan AverageExecutionTime { get; set; }
public long TotalMemoryAllocated { get; set; }
public string FastestTest { get; set; }
public string SlowestTest { get; set; }
public string MostMemoryIntensive { get; set; }
}
public class MemoryOptimizationReport
{
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public TimeSpan Duration { get; set; }
public int Iterations { get; set; }
public List<DetailedMemorySnapshot> MemorySnapshots { get; set; }
public List<GcEvent> GcEvents { get; set; }
public MemoryAnalysisResult Analysis { get; set; }
}
public class DetailedMemorySnapshot
{
public int Iteration { get; set; }
public DateTime Timestamp { get; set; }
public long MemoryBefore { get; set; }
public long MemoryAfter { get; set; }
public long MemoryDelta { get; set; }
public int Gen0Collections { get; set; }
public int Gen1Collections { get; set; }
public int Gen2Collections { get; set; }
}
public class GcEvent
{
public int Iteration { get; set; }
public DateTime Timestamp { get; set; }
public int Generation0Collections { get; set; }
public int Generation1Collections { get; set; }
public int Generation2Collections { get; set; }
public long MemoryBeforeGc { get; set; }
public long MemoryAfterGc { get; set; }
}
public class MemoryAnalysisResult
{
public long TotalMemoryAllocated { get; set; }
public double AverageMemoryPerIteration { get; set; }
public long MaxMemoryUsage { get; set; }
public double MemoryGrowthTrend { get; set; }
public int TotalGcCollections { get; set; }
public int Gen0Collections { get; set; }
public int Gen1Collections { get; set; }
public int Gen2Collections { get; set; }
public double GcPressure { get; set; }
public bool MemoryLeakSuspicion { get; set; }
public List<string> Recommendations { get; set; }
}
public class PerformanceMetricsCollector
{
// 简化的性能指标收集器
public void StartCollection() { }
public void StopCollection() { }
public PerformanceMetrics GetMetrics() => new PerformanceMetrics();
}
练习2:异步性能优化器
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
// 异步性能优化器
public class AsyncPerformanceOptimizer
{
private readonly SemaphoreSlim _semaphore;
private readonly ConcurrentQueue<AsyncOperationMetric> _metrics;
private readonly Timer _metricsTimer;
public AsyncPerformanceOptimizer(int maxConcurrency = Environment.ProcessorCount)
{
_semaphore = new SemaphoreSlim(maxConcurrency, maxConcurrency);
_metrics = new ConcurrentQueue<AsyncOperationMetric>();
_metricsTimer = new Timer(CollectMetrics, null, TimeSpan.Zero, TimeSpan.FromSeconds(1));
}
// 优化的并行处理
public async Task<List<TResult>> ProcessInParallelOptimized<TInput, TResult>(
IEnumerable<TInput> items,
Func<TInput, Task<TResult>> processor,
int? maxDegreeOfParallelism = null)
{
var itemList = items.ToList();
var results = new TResult[itemList.Count];
var semaphore = new SemaphoreSlim(maxDegreeOfParallelism ?? Environment.ProcessorCount);
var tasks = itemList.Select(async (item, index) =>
{
await semaphore.WaitAsync();
try
{
var stopwatch = Stopwatch.StartNew();
var result = await processor(item);
stopwatch.Stop();
_metrics.Enqueue(new AsyncOperationMetric
{
Timestamp = DateTime.UtcNow,
Duration = stopwatch.Elapsed,
ThreadId = Thread.CurrentThread.ManagedThreadId,
OperationType = "ParallelProcessing"
});
results[index] = result;
}
finally
{
semaphore.Release();
}
});
await Task.WhenAll(tasks);
return results.ToList();
}
// 批处理优化
public async Task<List<TResult>> ProcessInBatches<TInput, TResult>(
IEnumerable<TInput> items,
Func<IEnumerable<TInput>, Task<IEnumerable<TResult>>> batchProcessor,
int batchSize = 100)
{
var itemList = items.ToList();
var results = new List<TResult>();
for (int i = 0; i < itemList.Count; i += batchSize)
{
var batch = itemList.Skip(i).Take(batchSize);
var stopwatch = Stopwatch.StartNew();
var batchResults = await batchProcessor(batch);
results.AddRange(batchResults);
stopwatch.Stop();
_metrics.Enqueue(new AsyncOperationMetric
{
Timestamp = DateTime.UtcNow,
Duration = stopwatch.Elapsed,
ThreadId = Thread.CurrentThread.ManagedThreadId,
OperationType = "BatchProcessing",
BatchSize = batch.Count()
});
}
return results;
}
// 自适应限流
public async Task<T> ExecuteWithAdaptiveThrottling<T>(
Func<Task<T>> operation,
string operationName = "Unknown")
{
await _semaphore.WaitAsync();
try
{
var stopwatch = Stopwatch.StartNew();
var result = await operation();
stopwatch.Stop();
_metrics.Enqueue(new AsyncOperationMetric
{
Timestamp = DateTime.UtcNow,
Duration = stopwatch.Elapsed,
ThreadId = Thread.CurrentThread.ManagedThreadId,
OperationType = operationName,
Success = true
});
return result;
}
catch (Exception ex)
{
_metrics.Enqueue(new AsyncOperationMetric
{
Timestamp = DateTime.UtcNow,
ThreadId = Thread.CurrentThread.ManagedThreadId,
OperationType = operationName,
Success = false,
ErrorMessage = ex.Message
});
throw;
}
finally
{
_semaphore.Release();
}
}
// 缓存优化的异步操作
private readonly ConcurrentDictionary<string, CachedAsyncResult> _cache = new();
public async Task<T> ExecuteWithCache<T>(
string cacheKey,
Func<Task<T>> operation,
TimeSpan? cacheDuration = null)
{
var duration = cacheDuration ?? TimeSpan.FromMinutes(5);
if (_cache.TryGetValue(cacheKey, out var cached) &&
cached.ExpiresAt > DateTime.UtcNow)
{
_metrics.Enqueue(new AsyncOperationMetric
{
Timestamp = DateTime.UtcNow,
Duration = TimeSpan.Zero,
OperationType = "CacheHit",
CacheKey = cacheKey
});
return (T)cached.Result;
}
var stopwatch = Stopwatch.StartNew();
var result = await operation();
stopwatch.Stop();
_cache[cacheKey] = new CachedAsyncResult
{
Result = result,
ExpiresAt = DateTime.UtcNow.Add(duration)
};
_metrics.Enqueue(new AsyncOperationMetric
{
Timestamp = DateTime.UtcNow,
Duration = stopwatch.Elapsed,
OperationType = "CacheMiss",
CacheKey = cacheKey
});
return result;
}
// 性能报告生成
public AsyncPerformanceReport GenerateReport(TimeSpan? timeRange = null)
{
var cutoff = DateTime.UtcNow - (timeRange ?? TimeSpan.FromHours(1));
var recentMetrics = _metrics.Where(m => m.Timestamp >= cutoff).ToList();
if (!recentMetrics.Any())
{
return new AsyncPerformanceReport
{
GeneratedAt = DateTime.UtcNow,
TimeRange = timeRange ?? TimeSpan.FromHours(1),
Message = "No metrics available for the specified time range"
};
}
var groupedByOperation = recentMetrics.GroupBy(m => m.OperationType).ToList();
return new AsyncPerformanceReport
{
GeneratedAt = DateTime.UtcNow,
TimeRange = timeRange ?? TimeSpan.FromHours(1),
TotalOperations = recentMetrics.Count,
SuccessfulOperations = recentMetrics.Count(m => m.Success),
FailedOperations = recentMetrics.Count(m => !m.Success),
AverageExecutionTime = TimeSpan.FromMilliseconds(
recentMetrics.Where(m => m.Duration.HasValue)
.Average(m => m.Duration.Value.TotalMilliseconds)),
OperationBreakdown = groupedByOperation.Select(g => new OperationBreakdown
{
OperationType = g.Key,
Count = g.Count(),
AverageExecutionTime = TimeSpan.FromMilliseconds(
g.Where(m => m.Duration.HasValue)
.Average(m => m.Duration.Value.TotalMilliseconds)),
SuccessRate = g.Count(m => m.Success) / (double)g.Count(),
UniqueThreads = g.Select(m => m.ThreadId).Distinct().Count()
}).ToList(),
CacheMetrics = CalculateCacheMetrics(recentMetrics),
ThreadUtilization = CalculateThreadUtilization(recentMetrics),
Recommendations = GenerateAsyncRecommendations(recentMetrics)
};
}
private CacheMetrics CalculateCacheMetrics(List<AsyncOperationMetric> metrics)
{
var cacheOperations = metrics.Where(m => m.OperationType == "CacheHit" || m.OperationType == "CacheMiss").ToList();
if (!cacheOperations.Any())
return new CacheMetrics();
var hits = cacheOperations.Count(m => m.OperationType == "CacheHit");
var misses = cacheOperations.Count(m => m.OperationType == "CacheMiss");
return new CacheMetrics
{
TotalRequests = hits + misses,
CacheHits = hits,
CacheMisses = misses,
HitRate = hits / (double)(hits + misses)
};
}
private ThreadUtilizationMetrics CalculateThreadUtilization(List<AsyncOperationMetric> metrics)
{
var threadGroups = metrics.GroupBy(m => m.ThreadId).ToList();
return new ThreadUtilizationMetrics
{
UniqueThreadsUsed = threadGroups.Count,
AverageOperationsPerThread = threadGroups.Average(g => g.Count()),
MaxOperationsOnSingleThread = threadGroups.Max(g => g.Count()),
ThreadDistribution = threadGroups.ToDictionary(
g => g.Key,
g => g.Count())
};
}
private List<string> GenerateAsyncRecommendations(List<AsyncOperationMetric> metrics)
{
var recommendations = new List<string>();
var avgDuration = metrics.Where(m => m.Duration.HasValue)
.Average(m => m.Duration.Value.TotalMilliseconds);
if (avgDuration > 1000)
{
recommendations.Add("Consider implementing caching for long-running operations");
}
var failureRate = metrics.Count(m => !m.Success) / (double)metrics.Count;
if (failureRate > 0.05)
{
recommendations.Add("High failure rate detected. Implement retry policies and circuit breakers");
}
var threadUtilization = CalculateThreadUtilization(metrics);
if (threadUtilization.MaxOperationsOnSingleThread > threadUtilization.AverageOperationsPerThread * 3)
{
recommendations.Add("Uneven thread utilization detected. Review task distribution");
}
var cacheMetrics = CalculateCacheMetrics(metrics);
if (cacheMetrics.TotalRequests > 0 && cacheMetrics.HitRate < 0.7)
{
recommendations.Add("Low cache hit rate. Review cache key strategy and expiration policies");
}
return recommendations;
}
private void CollectMetrics(object state)
{
// 清理过期的指标数据
var cutoff = DateTime.UtcNow.AddHours(-24);
var metricsToKeep = new List<AsyncOperationMetric>();
while (_metrics.TryDequeue(out var metric))
{
if (metric.Timestamp >= cutoff)
{
metricsToKeep.Add(metric);
}
}
foreach (var metric in metricsToKeep)
{
_metrics.Enqueue(metric);
}
// 清理过期的缓存
var expiredKeys = _cache.Where(kvp => kvp.Value.ExpiresAt <= DateTime.UtcNow)
.Select(kvp => kvp.Key)
.ToList();
foreach (var key in expiredKeys)
{
_cache.TryRemove(key, out _);
}
}
public void Dispose()
{
_semaphore?.Dispose();
_metricsTimer?.Dispose();
}
}
// 异步性能优化相关数据模型
public class AsyncOperationMetric
{
public DateTime Timestamp { get; set; }
public TimeSpan? Duration { get; set; }
public int ThreadId { get; set; }
public string OperationType { get; set; }
public bool Success { get; set; } = true;
public string ErrorMessage { get; set; }
public string CacheKey { get; set; }
public int BatchSize { get; set; }
}
public class CachedAsyncResult
{
public object Result { get; set; }
public DateTime ExpiresAt { get; set; }
}
public class AsyncPerformanceReport
{
public DateTime GeneratedAt { get; set; }
public TimeSpan TimeRange { get; set; }
public string Message { get; set; }
public int TotalOperations { get; set; }
public int SuccessfulOperations { get; set; }
public int FailedOperations { get; set; }
public TimeSpan AverageExecutionTime { get; set; }
public List<OperationBreakdown> OperationBreakdown { get; set; }
public CacheMetrics CacheMetrics { get; set; }
public ThreadUtilizationMetrics ThreadUtilization { get; set; }
public List<string> Recommendations { get; set; }
}
public class OperationBreakdown
{
public string OperationType { get; set; }
public int Count { get; set; }
public TimeSpan AverageExecutionTime { get; set; }
public double SuccessRate { get; set; }
public int UniqueThreads { get; set; }
}
public class CacheMetrics
{
public int TotalRequests { get; set; }
public int CacheHits { get; set; }
public int CacheMisses { get; set; }
public double HitRate { get; set; }
}
public class ThreadUtilizationMetrics
{
public int UniqueThreadsUsed { get; set; }
public double AverageOperationsPerThread { get; set; }
public int MaxOperationsOnSingleThread { get; set; }
public Dictionary<int, int> ThreadDistribution { get; set; }
}
21.9 本章总结
本章深入探讨了C#应用程序的性能优化和调试技术,涵盖了以下核心内容:
核心概念
性能分析和诊断
- 性能指标收集和分析
- 系统资源监控
- 瓶颈识别和定位
内存管理和垃圾回收优化
- 对象池模式实现
- 内存使用分析
- GC压力优化
- 内存泄漏检测
异步编程性能优化
- 异步操作性能分析
- 线程池使用优化
- 异步反模式识别
- 批处理和限流策略
数据库查询优化
- 查询性能分析
- EF Core优化技术
- 连接池监控
- N+1问题解决
缓存策略和实现
- 多级缓存系统
- 缓存预热策略
- 智能缓存选择
- 缓存性能监控
调试技术和工具
- 调试信息收集
- 性能分析器
- 方法执行追踪
- 异常分析
性能监控和分析
- 实时性能监控
- 告警系统设计
- 趋势分析
- 性能报告生成
高级技术
综合性能分析工具
- 多维度性能测试
- 统计分析和报告
- 性能基准测试
内存优化分析器
- 内存使用模式分析
- GC事件监控
- 内存泄漏检测
- 优化建议生成
异步性能优化器
- 并行处理优化
- 自适应限流
- 缓存集成
- 性能指标收集
实际应用
企业级性能优化
- 大规模应用性能调优
- 生产环境监控
- 性能问题诊断
微服务性能优化
- 分布式系统性能分析
- 服务间通信优化
- 资源使用优化
高并发场景优化
- 并发控制策略
- 资源竞争优化
- 扩展性设计
重要技能
性能分析能力
- 性能瓶颈识别
- 根因分析
- 优化策略制定
监控体系建设
- 指标体系设计
- 告警策略配置
- 可视化展示
调试技能掌握
- 调试工具使用
- 问题定位技巧
- 日志分析能力
通过本章的学习,您应该能够: - 设计和实现高效的性能监控系统 - 识别和解决各种性能问题 - 优化内存使用和垃圾回收 - 提升异步编程性能 - 构建可扩展的高性能应用
下一章我们将学习C#的高级特性和最新功能,探索语言的前沿技术和最佳实践。
## 21.8 实践练习
### 练习1:性能分析工具
```csharp
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
// 综合性能分析工具
public class ComprehensivePerformanceAnalyzer
{
private readonly List<PerformanceTest> _tests;
private readonly PerformanceMetricsCollector _metricsCollector;
public ComprehensivePerformanceAnalyzer()
{
_tests = new List<PerformanceTest>();
_metricsCollector = new PerformanceMetricsCollector();
}
public void AddTest(string name, Func<Task> testAction, int iterations = 1000)
{
_tests.Add(new PerformanceTest
{
Name = name,
TestAction = testAction,
Iterations = iterations
});
}
public async Task<ComprehensivePerformanceReport> RunAllTests()
{
var report = new ComprehensivePerformanceReport
{
StartTime = DateTime.UtcNow,
TestResults = new List<PerformanceTestResult>()
};
foreach (var test in _tests)
{
Console.WriteLine($"Running test: {test.Name}");
var result = await RunSingleTest(test);
report.TestResults.Add(result);
// 在测试之间稍作停顿,让GC有机会清理
await Task.Delay(100);
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
report.EndTime = DateTime.UtcNow;
report.TotalDuration = report.EndTime - report.StartTime;
report.Summary = GenerateSummary(report.TestResults);
return report;
}
private async Task<PerformanceTestResult> RunSingleTest(PerformanceTest test)
{
var result = new PerformanceTestResult
{
TestName = test.Name,
Iterations = test.Iterations,
ExecutionTimes = new List<TimeSpan>(),
MemorySnapshots = new List<MemorySnapshot>()
};
// 预热
for (int i = 0; i < Math.Min(10, test.Iterations / 10); i++)
{
await test.TestAction();
}
// 清理内存
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
var initialMemory = GC.GetTotalMemory(false);
// 执行实际测试
for (int i = 0; i < test.Iterations; i++)
{
var stopwatch = Stopwatch.StartNew();
var memoryBefore = GC.GetTotalMemory(false);
try
{
await test.TestAction();
stopwatch.Stop();
result.ExecutionTimes.Add(stopwatch.Elapsed);
result.SuccessfulIterations++;
}
catch (Exception ex)
{
stopwatch.Stop();
result.FailedIterations++;
result.Errors.Add(ex.Message);
}
var memoryAfter = GC.GetTotalMemory(false);
result.MemorySnapshots.Add(new MemorySnapshot
{
Iteration = i,
MemoryBefore = memoryBefore,
MemoryAfter = memoryAfter,
MemoryDelta = memoryAfter - memoryBefore
});
// 每100次迭代检查一次内存压力
if (i % 100 == 0 && i > 0)
{
var currentMemory = GC.GetTotalMemory(false);
if (currentMemory > initialMemory * 2) // 内存增长超过2倍
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
}
}
// 计算统计信息
if (result.ExecutionTimes.Any())
{
var sortedTimes = result.ExecutionTimes.OrderBy(t => t.TotalMilliseconds).ToList();
result.MinExecutionTime = sortedTimes.First();
result.MaxExecutionTime = sortedTimes.Last();
result.AverageExecutionTime = TimeSpan.FromMilliseconds(sortedTimes.Average(t => t.TotalMilliseconds));
result.MedianExecutionTime = sortedTimes[sortedTimes.Count / 2];
result.Percentile95 = sortedTimes[(int)(sortedTimes.Count * 0.95)];
result.Percentile99 = sortedTimes[(int)(sortedTimes.Count * 0.99)];
}
if (result.MemorySnapshots.Any())
{
result.TotalMemoryAllocated = result.MemorySnapshots.Sum(s => Math.Max(0, s.MemoryDelta));
result.AverageMemoryPerIteration = result.TotalMemoryAllocated / result.Iterations;
}
result.ThroughputPerSecond = result.SuccessfulIterations / result.ExecutionTimes.Sum(t => t.TotalSeconds);
return result;
}
private PerformanceSummary GenerateSummary(List<PerformanceTestResult> results)
{
return new PerformanceSummary
{
TotalTests = results.Count,
TotalIterations = results.Sum(r => r.Iterations),
TotalSuccessfulIterations = results.Sum(r => r.SuccessfulIterations),
TotalFailedIterations = results.Sum(r => r.FailedIterations),
AverageExecutionTime = TimeSpan.FromMilliseconds(
results.Where(r => r.ExecutionTimes.Any())
.SelectMany(r => r.ExecutionTimes)
.Average(t => t.TotalMilliseconds)),
TotalMemoryAllocated = results.Sum(r => r.TotalMemoryAllocated),
FastestTest = results.Where(r => r.ExecutionTimes.Any())
.OrderBy(r => r.AverageExecutionTime)
.FirstOrDefault()?.TestName,
SlowestTest = results.Where(r => r.ExecutionTimes.Any())
.OrderByDescending(r => r.AverageExecutionTime)
.FirstOrDefault()?.TestName,
MostMemoryIntensive = results.OrderByDescending(r => r.AverageMemoryPerIteration)
.FirstOrDefault()?.TestName
};
}
}
// 内存优化分析器
public class MemoryOptimizationAnalyzer
{
public async Task<MemoryOptimizationReport> AnalyzeMemoryUsage(Func<Task> operation, int iterations = 1000)
{
var report = new MemoryOptimizationReport
{
StartTime = DateTime.UtcNow,
Iterations = iterations,
MemorySnapshots = new List<DetailedMemorySnapshot>(),
GcEvents = new List<GcEvent>()
};
// 订阅GC事件(简化版本)
var initialGen0 = GC.CollectionCount(0);
var initialGen1 = GC.CollectionCount(1);
var initialGen2 = GC.CollectionCount(2);
// 强制GC并获取基线
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
var baselineMemory = GC.GetTotalMemory(false);
for (int i = 0; i < iterations; i++)
{
var memoryBefore = GC.GetTotalMemory(false);
var gen0Before = GC.CollectionCount(0);
var gen1Before = GC.CollectionCount(1);
var gen2Before = GC.CollectionCount(2);
await operation();
var memoryAfter = GC.GetTotalMemory(false);
var gen0After = GC.CollectionCount(0);
var gen1After = GC.CollectionCount(1);
var gen2After = GC.CollectionCount(2);
report.MemorySnapshots.Add(new DetailedMemorySnapshot
{
Iteration = i,
Timestamp = DateTime.UtcNow,
MemoryBefore = memoryBefore,
MemoryAfter = memoryAfter,
MemoryDelta = memoryAfter - memoryBefore,
Gen0Collections = gen0After - gen0Before,
Gen1Collections = gen1After - gen1Before,
Gen2Collections = gen2After - gen2Before
});
// 记录GC事件
if (gen0After > gen0Before || gen1After > gen1Before || gen2After > gen2Before)
{
report.GcEvents.Add(new GcEvent
{
Iteration = i,
Timestamp = DateTime.UtcNow,
Generation0Collections = gen0After - gen0Before,
Generation1Collections = gen1After - gen1Before,
Generation2Collections = gen2After - gen2Before,
MemoryBeforeGc = memoryBefore,
MemoryAfterGc = memoryAfter
});
}
}
report.EndTime = DateTime.UtcNow;
report.Duration = report.EndTime - report.StartTime;
// 分析结果
report.Analysis = AnalyzeMemoryPatterns(report);
return report;
}
private MemoryAnalysisResult AnalyzeMemoryPatterns(MemoryOptimizationReport report)
{
var snapshots = report.MemorySnapshots;
var gcEvents = report.GcEvents;
return new MemoryAnalysisResult
{
TotalMemoryAllocated = snapshots.Sum(s => Math.Max(0, s.MemoryDelta)),
AverageMemoryPerIteration = snapshots.Average(s => Math.Max(0, s.MemoryDelta)),
MaxMemoryUsage = snapshots.Max(s => s.MemoryAfter),
MemoryGrowthTrend = CalculateMemoryGrowthTrend(snapshots),
TotalGcCollections = gcEvents.Sum(e => e.Generation0Collections + e.Generation1Collections + e.Generation2Collections),
Gen0Collections = gcEvents.Sum(e => e.Generation0Collections),
Gen1Collections = gcEvents.Sum(e => e.Generation1Collections),
Gen2Collections = gcEvents.Sum(e => e.Generation2Collections),
GcPressure = CalculateGcPressure(gcEvents, report.Duration),
MemoryLeakSuspicion = DetectMemoryLeakSuspicion(snapshots),
Recommendations = GenerateMemoryRecommendations(snapshots, gcEvents)
};
}
private double CalculateMemoryGrowthTrend(List<DetailedMemorySnapshot> snapshots)
{
if (snapshots.Count < 2) return 0;
var memoryValues = snapshots.Select(s => (double)s.MemoryAfter).ToList();
var n = memoryValues.Count;
var sumX = Enumerable.Range(0, n).Sum();
var sumY = memoryValues.Sum();
var sumXY = memoryValues.Select((y, x) => x * y).Sum();
var sumX2 = Enumerable.Range(0, n).Select(x => x * x).Sum();
return (n * sumXY - sumX * sumY) / (double)(n * sumX2 - sumX * sumX);
}
private double CalculateGcPressure(List<GcEvent> gcEvents, TimeSpan duration)
{
if (duration.TotalMinutes == 0) return 0;
var totalCollections = gcEvents.Sum(e => e.Generation0Collections + e.Generation1Collections + e.Generation2Collections);
return totalCollections / duration.TotalMinutes;
}
private bool DetectMemoryLeakSuspicion(List<DetailedMemorySnapshot> snapshots)
{
if (snapshots.Count < 100) return false;
// 检查最后25%的快照是否显示持续的内存增长
var lastQuarter = snapshots.TakeLast(snapshots.Count / 4).ToList();
var trend = CalculateMemoryGrowthTrend(lastQuarter);
return trend > 1000; // 如果趋势显示每次迭代增长超过1KB,可能存在内存泄漏
}
private List<string> GenerateMemoryRecommendations(List<DetailedMemorySnapshot> snapshots, List<GcEvent> gcEvents)
{
var recommendations = new List<string>();
var avgMemoryPerIteration = snapshots.Average(s => Math.Max(0, s.MemoryDelta));
if (avgMemoryPerIteration > 10000) // 每次迭代超过10KB
{
recommendations.Add("Consider implementing object pooling to reduce memory allocations");
}
var gcPressure = gcEvents.Count / (double)snapshots.Count;
if (gcPressure > 0.1) // 超过10%的迭代触发GC
{
recommendations.Add("High GC pressure detected. Review allocation patterns and consider using value types");
}
var gen2Collections = gcEvents.Sum(e => e.Generation2Collections);
if (gen2Collections > 0)
{
recommendations.Add("Generation 2 collections detected. Review long-lived object usage");
}
if (DetectMemoryLeakSuspicion(snapshots))
{
recommendations.Add("Potential memory leak detected. Review object disposal and event handler cleanup");
}
return recommendations;
}
}
21.7 性能监控和分析
实时性能监控
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
// 实时性能监控服务
public class RealTimePerformanceMonitor : BackgroundService
{
private readonly ILogger<RealTimePerformanceMonitor> _logger;
private readonly PerformanceCounterManager _counterManager;
private readonly AlertManager _alertManager;
private readonly ConcurrentQueue<PerformanceSnapshot> _snapshots;
private readonly Timer _snapshotTimer;
public RealTimePerformanceMonitor(
ILogger<RealTimePerformanceMonitor> logger,
PerformanceCounterManager counterManager,
AlertManager alertManager)
{
_logger = logger;
_counterManager = counterManager;
_alertManager = alertManager;
_snapshots = new ConcurrentQueue<PerformanceSnapshot>();
_snapshotTimer = new Timer(TakeSnapshot, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
await AnalyzePerformance();
await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in performance monitoring");
}
}
}
private void TakeSnapshot(object state)
{
try
{
var snapshot = new PerformanceSnapshot
{
Timestamp = DateTime.UtcNow,
CpuUsage = _counterManager.GetCpuUsage(),
MemoryUsage = _counterManager.GetMemoryUsage(),
GcCollections = _counterManager.GetGcCollections(),
ThreadCount = _counterManager.GetThreadCount(),
HandleCount = _counterManager.GetHandleCount(),
RequestsPerSecond = _counterManager.GetRequestsPerSecond(),
AverageResponseTime = _counterManager.GetAverageResponseTime()
};
_snapshots.Enqueue(snapshot);
// 保持最近1000个快照
while (_snapshots.Count > 1000)
{
_snapshots.TryDequeue(out _);
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to take performance snapshot");
}
}
private async Task AnalyzePerformance()
{
var recentSnapshots = _snapshots.ToArray().TakeLast(60).ToList(); // 最近5分钟
if (recentSnapshots.Count < 10) return;
// CPU 使用率分析
var avgCpu = recentSnapshots.Average(s => s.CpuUsage);
if (avgCpu > 80)
{
await _alertManager.SendAlert(new PerformanceAlert
{
Type = AlertType.HighCpuUsage,
Message = $"High CPU usage detected: {avgCpu:F1}%",
Severity = avgCpu > 95 ? AlertSeverity.Critical : AlertSeverity.Warning,
Timestamp = DateTime.UtcNow,
Value = avgCpu
});
}
// 内存使用率分析
var avgMemory = recentSnapshots.Average(s => s.MemoryUsage);
if (avgMemory > 80)
{
await _alertManager.SendAlert(new PerformanceAlert
{
Type = AlertType.HighMemoryUsage,
Message = $"High memory usage detected: {avgMemory:F1}%",
Severity = avgMemory > 95 ? AlertSeverity.Critical : AlertSeverity.Warning,
Timestamp = DateTime.UtcNow,
Value = avgMemory
});
}
// 响应时间分析
var avgResponseTime = recentSnapshots.Average(s => s.AverageResponseTime);
if (avgResponseTime > 1000) // 超过1秒
{
await _alertManager.SendAlert(new PerformanceAlert
{
Type = AlertType.SlowResponse,
Message = $"Slow response time detected: {avgResponseTime:F0}ms",
Severity = avgResponseTime > 5000 ? AlertSeverity.Critical : AlertSeverity.Warning,
Timestamp = DateTime.UtcNow,
Value = avgResponseTime
});
}
// GC 压力分析
var recentGcCollections = recentSnapshots.TakeLast(12).ToList(); // 最近1分钟
if (recentGcCollections.Count >= 2)
{
var gcIncrease = recentGcCollections.Last().GcCollections - recentGcCollections.First().GcCollections;
if (gcIncrease > 10) // 1分钟内超过10次GC
{
await _alertManager.SendAlert(new PerformanceAlert
{
Type = AlertType.HighGcPressure,
Message = $"High GC pressure detected: {gcIncrease} collections in 1 minute",
Severity = AlertSeverity.Warning,
Timestamp = DateTime.UtcNow,
Value = gcIncrease
});
}
}
}
public PerformanceAnalysisReport GenerateReport(TimeSpan timeRange)
{
var cutoff = DateTime.UtcNow - timeRange;
var snapshots = _snapshots.Where(s => s.Timestamp >= cutoff).ToList();
if (!snapshots.Any())
{
return new PerformanceAnalysisReport
{
GeneratedAt = DateTime.UtcNow,
TimeRange = timeRange,
Message = "No data available for the specified time range"
};
}
return new PerformanceAnalysisReport
{
GeneratedAt = DateTime.UtcNow,
TimeRange = timeRange,
SnapshotCount = snapshots.Count,
CpuAnalysis = new MetricAnalysis
{
Average = snapshots.Average(s => s.CpuUsage),
Minimum = snapshots.Min(s => s.CpuUsage),
Maximum = snapshots.Max(s => s.CpuUsage),
StandardDeviation = CalculateStandardDeviation(snapshots.Select(s => s.CpuUsage))
},
MemoryAnalysis = new MetricAnalysis
{
Average = snapshots.Average(s => s.MemoryUsage),
Minimum = snapshots.Min(s => s.MemoryUsage),
Maximum = snapshots.Max(s => s.MemoryUsage),
StandardDeviation = CalculateStandardDeviation(snapshots.Select(s => s.MemoryUsage))
},
ResponseTimeAnalysis = new MetricAnalysis
{
Average = snapshots.Average(s => s.AverageResponseTime),
Minimum = snapshots.Min(s => s.AverageResponseTime),
Maximum = snapshots.Max(s => s.AverageResponseTime),
StandardDeviation = CalculateStandardDeviation(snapshots.Select(s => s.AverageResponseTime))
},
ThroughputAnalysis = new MetricAnalysis
{
Average = snapshots.Average(s => s.RequestsPerSecond),
Minimum = snapshots.Min(s => s.RequestsPerSecond),
Maximum = snapshots.Max(s => s.RequestsPerSecond),
StandardDeviation = CalculateStandardDeviation(snapshots.Select(s => s.RequestsPerSecond))
},
Trends = AnalyzeTrends(snapshots),
Recommendations = GenerateRecommendations(snapshots)
};
}
private double CalculateStandardDeviation(IEnumerable<double> values)
{
var valueList = values.ToList();
if (valueList.Count <= 1) return 0;
var average = valueList.Average();
var sumOfSquaresOfDifferences = valueList.Select(val => (val - average) * (val - average)).Sum();
return Math.Sqrt(sumOfSquaresOfDifferences / valueList.Count);
}
private List<TrendAnalysis> AnalyzeTrends(List<PerformanceSnapshot> snapshots)
{
var trends = new List<TrendAnalysis>();
if (snapshots.Count < 10) return trends;
// CPU 趋势分析
var cpuTrend = CalculateTrend(snapshots.Select(s => s.CpuUsage).ToList());
trends.Add(new TrendAnalysis
{
Metric = "CPU Usage",
Direction = cpuTrend > 0.1 ? TrendDirection.Increasing :
cpuTrend < -0.1 ? TrendDirection.Decreasing : TrendDirection.Stable,
Slope = cpuTrend,
Confidence = CalculateTrendConfidence(snapshots.Select(s => s.CpuUsage).ToList())
});
// 内存趋势分析
var memoryTrend = CalculateTrend(snapshots.Select(s => s.MemoryUsage).ToList());
trends.Add(new TrendAnalysis
{
Metric = "Memory Usage",
Direction = memoryTrend > 0.1 ? TrendDirection.Increasing :
memoryTrend < -0.1 ? TrendDirection.Decreasing : TrendDirection.Stable,
Slope = memoryTrend,
Confidence = CalculateTrendConfidence(snapshots.Select(s => s.MemoryUsage).ToList())
});
return trends;
}
private double CalculateTrend(List<double> values)
{
if (values.Count < 2) return 0;
var n = values.Count;
var sumX = Enumerable.Range(0, n).Sum();
var sumY = values.Sum();
var sumXY = values.Select((y, x) => x * y).Sum();
var sumX2 = Enumerable.Range(0, n).Select(x => x * x).Sum();
return (n * sumXY - sumX * sumY) / (double)(n * sumX2 - sumX * sumX);
}
private double CalculateTrendConfidence(List<double> values)
{
// 简化的置信度计算,基于数据的一致性
if (values.Count < 3) return 0;
var trend = CalculateTrend(values);
var predictions = values.Select((_, i) => trend * i).ToList();
var errors = values.Zip(predictions, (actual, predicted) => Math.Abs(actual - predicted)).ToList();
var avgError = errors.Average();
var maxValue = values.Max();
return Math.Max(0, 1 - (avgError / maxValue));
}
private List<PerformanceRecommendation> GenerateRecommendations(List<PerformanceSnapshot> snapshots)
{
var recommendations = new List<PerformanceRecommendation>();
var avgCpu = snapshots.Average(s => s.CpuUsage);
var avgMemory = snapshots.Average(s => s.MemoryUsage);
var avgResponseTime = snapshots.Average(s => s.AverageResponseTime);
if (avgCpu > 70)
{
recommendations.Add(new PerformanceRecommendation
{
Type = RecommendationType.CpuOptimization,
Priority = avgCpu > 90 ? RecommendationPriority.High : RecommendationPriority.Medium,
Description = "High CPU usage detected",
Suggestion = "Consider optimizing CPU-intensive operations, implementing caching, or scaling horizontally"
});
}
if (avgMemory > 70)
{
recommendations.Add(new PerformanceRecommendation
{
Type = RecommendationType.MemoryOptimization,
Priority = avgMemory > 90 ? RecommendationPriority.High : RecommendationPriority.Medium,
Description = "High memory usage detected",
Suggestion = "Review memory allocation patterns, implement object pooling, or increase available memory"
});
}
if (avgResponseTime > 500)
{
recommendations.Add(new PerformanceRecommendation
{
Type = RecommendationType.ResponseTimeOptimization,
Priority = avgResponseTime > 2000 ? RecommendationPriority.High : RecommendationPriority.Medium,
Description = "Slow response times detected",
Suggestion = "Optimize database queries, implement caching, or review async/await patterns"
});
}
return recommendations;
}
public override void Dispose()
{
_snapshotTimer?.Dispose();
base.Dispose();
}
}
// 性能计数器管理器
public class PerformanceCounterManager
{
private readonly PerformanceCounter _cpuCounter;
private readonly PerformanceCounter _memoryCounter;
private readonly PerformanceCounter _gcCounter;
private readonly Process _currentProcess;
private readonly ConcurrentQueue<RequestMetric> _requestMetrics;
public PerformanceCounterManager()
{
_cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
_memoryCounter = new PerformanceCounter("Memory", "Available MBytes");
_gcCounter = new PerformanceCounter(".NET CLR Memory", "# Gen 0 Collections", Process.GetCurrentProcess().ProcessName);
_currentProcess = Process.GetCurrentProcess();
_requestMetrics = new ConcurrentQueue<RequestMetric>();
}
public double GetCpuUsage()
{
try
{
return _cpuCounter.NextValue();
}
catch
{
return 0;
}
}
public double GetMemoryUsage()
{
try
{
var totalMemory = GC.GetTotalMemory(false);
var workingSet = _currentProcess.WorkingSet64;
return (double)workingSet / (1024 * 1024 * 1024) * 100; // 转换为GB并计算百分比
}
catch
{
return 0;
}
}
public int GetGcCollections()
{
try
{
return GC.CollectionCount(0) + GC.CollectionCount(1) + GC.CollectionCount(2);
}
catch
{
return 0;
}
}
public int GetThreadCount()
{
try
{
return _currentProcess.Threads.Count;
}
catch
{
return 0;
}
}
public int GetHandleCount()
{
try
{
return _currentProcess.HandleCount;
}
catch
{
return 0;
}
}
public void RecordRequest(TimeSpan responseTime)
{
_requestMetrics.Enqueue(new RequestMetric
{
Timestamp = DateTime.UtcNow,
ResponseTime = responseTime
});
// 保持最近1000个请求记录
while (_requestMetrics.Count > 1000)
{
_requestMetrics.TryDequeue(out _);
}
}
public double GetRequestsPerSecond()
{
var oneMinuteAgo = DateTime.UtcNow.AddMinutes(-1);
var recentRequests = _requestMetrics.Where(r => r.Timestamp >= oneMinuteAgo).Count();
return recentRequests / 60.0;
}
public double GetAverageResponseTime()
{
var oneMinuteAgo = DateTime.UtcNow.AddMinutes(-1);
var recentRequests = _requestMetrics.Where(r => r.Timestamp >= oneMinuteAgo).ToList();
return recentRequests.Any() ? recentRequests.Average(r => r.ResponseTime.TotalMilliseconds) : 0;
}
public void Dispose()
{
_cpuCounter?.Dispose();
_memoryCounter?.Dispose();
_gcCounter?.Dispose();
_currentProcess?.Dispose();
}
}
// 告警管理器
public class AlertManager
{
private readonly ILogger<AlertManager> _logger;
private readonly List<IAlertChannel> _alertChannels;
private readonly ConcurrentDictionary<string, DateTime> _lastAlertTimes;
private readonly TimeSpan _alertCooldown = TimeSpan.FromMinutes(5);
public AlertManager(ILogger<AlertManager> logger, IEnumerable<IAlertChannel> alertChannels)
{
_logger = logger;
_alertChannels = alertChannels.ToList();
_lastAlertTimes = new ConcurrentDictionary<string, DateTime>();
}
public async Task SendAlert(PerformanceAlert alert)
{
var alertKey = $"{alert.Type}_{alert.Severity}";
// 检查冷却时间
if (_lastAlertTimes.TryGetValue(alertKey, out var lastTime) &&
DateTime.UtcNow - lastTime < _alertCooldown)
{
return;
}
_lastAlertTimes[alertKey] = DateTime.UtcNow;
_logger.LogWarning($"Performance alert: {alert.Message}");
var tasks = _alertChannels.Select(channel => channel.SendAlert(alert));
await Task.WhenAll(tasks);
}
}
// 告警通道接口
public interface IAlertChannel
{
Task SendAlert(PerformanceAlert alert);
}
// 邮件告警通道
public class EmailAlertChannel : IAlertChannel
{
private readonly ILogger<EmailAlertChannel> _logger;
public EmailAlertChannel(ILogger<EmailAlertChannel> logger)
{
_logger = logger;
}
public async Task SendAlert(PerformanceAlert alert)
{
try
{
// 实际的邮件发送逻辑
_logger.LogInformation($"Email alert sent: {alert.Message}");
await Task.Delay(100); // 模拟发送延迟
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to send email alert");
}
}
}
// Slack告警通道
public class SlackAlertChannel : IAlertChannel
{
private readonly ILogger<SlackAlertChannel> _logger;
public SlackAlertChannel(ILogger<SlackAlertChannel> logger)
{
_logger = logger;
}
public async Task SendAlert(PerformanceAlert alert)
{
try
{
// 实际的Slack消息发送逻辑
_logger.LogInformation($"Slack alert sent: {alert.Message}");
await Task.Delay(100); // 模拟发送延迟
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to send Slack alert");
}
}
}
21.5 缓存策略和实现
多级缓存系统
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using StackExchange.Redis;
// 多级缓存管理器
public class MultiLevelCacheManager
{
private readonly IMemoryCache _memoryCache;
private readonly IDistributedCache _distributedCache;
private readonly ILogger<MultiLevelCacheManager> _logger;
private readonly CacheConfiguration _config;
private readonly CacheMetrics _metrics;
public MultiLevelCacheManager(
IMemoryCache memoryCache,
IDistributedCache distributedCache,
ILogger<MultiLevelCacheManager> logger,
CacheConfiguration config)
{
_memoryCache = memoryCache;
_distributedCache = distributedCache;
_logger = logger;
_config = config;
_metrics = new CacheMetrics();
}
public async Task<T> GetAsync<T>(string key, Func<Task<T>> factory, CacheOptions options = null)
{
options ??= _config.DefaultOptions;
// 1. 尝试从内存缓存获取
if (_memoryCache.TryGetValue(key, out T memoryValue))
{
_metrics.RecordHit(CacheLevel.Memory);
_logger.LogDebug($"Cache hit (Memory): {key}");
return memoryValue;
}
// 2. 尝试从分布式缓存获取
try
{
var distributedValue = await _distributedCache.GetAsync(key);
if (distributedValue != null)
{
var deserializedValue = System.Text.Json.JsonSerializer.Deserialize<T>(distributedValue);
// 回填到内存缓存
_memoryCache.Set(key, deserializedValue, options.MemoryExpiration);
_metrics.RecordHit(CacheLevel.Distributed);
_logger.LogDebug($"Cache hit (Distributed): {key}");
return deserializedValue;
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, $"Failed to get from distributed cache: {key}");
}
// 3. 缓存未命中,执行工厂方法
_metrics.RecordMiss();
_logger.LogDebug($"Cache miss: {key}");
var value = await factory();
// 4. 存储到缓存
await SetAsync(key, value, options);
return value;
}
public async Task SetAsync<T>(string key, T value, CacheOptions options = null)
{
options ??= _config.DefaultOptions;
// 存储到内存缓存
_memoryCache.Set(key, value, options.MemoryExpiration);
// 存储到分布式缓存
try
{
var serializedValue = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(value);
await _distributedCache.SetAsync(key, serializedValue, new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = options.DistributedExpiration
});
}
catch (Exception ex)
{
_logger.LogWarning(ex, $"Failed to set distributed cache: {key}");
}
}
public async Task RemoveAsync(string key)
{
_memoryCache.Remove(key);
try
{
await _distributedCache.RemoveAsync(key);
}
catch (Exception ex)
{
_logger.LogWarning(ex, $"Failed to remove from distributed cache: {key}");
}
}
public async Task InvalidatePatternAsync(string pattern)
{
// 内存缓存模式失效(简化实现)
if (_memoryCache is MemoryCache mc)
{
var field = typeof(MemoryCache).GetField("_coherentState",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var coherentState = field?.GetValue(mc);
var entriesCollection = coherentState?.GetType()
.GetProperty("EntriesCollection", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var entries = (IDictionary)entriesCollection?.GetValue(coherentState);
if (entries != null)
{
var keysToRemove = new List<object>();
foreach (DictionaryEntry entry in entries)
{
if (entry.Key.ToString().Contains(pattern))
{
keysToRemove.Add(entry.Key);
}
}
foreach (var key in keysToRemove)
{
_memoryCache.Remove(key);
}
}
}
// Redis 分布式缓存模式失效
if (_distributedCache is IDatabase redis)
{
try
{
var server = redis.Multiplexer.GetServer(redis.Multiplexer.GetEndPoints().First());
var keys = server.Keys(pattern: $"*{pattern}*");
foreach (var key in keys)
{
await redis.KeyDeleteAsync(key);
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, $"Failed to invalidate pattern in Redis: {pattern}");
}
}
}
public CacheMetricsReport GetMetrics()
{
return _metrics.GenerateReport();
}
}
// 缓存预热器
public class CacheWarmer
{
private readonly MultiLevelCacheManager _cacheManager;
private readonly ILogger<CacheWarmer> _logger;
private readonly List<CacheWarmupTask> _warmupTasks;
public CacheWarmer(MultiLevelCacheManager cacheManager, ILogger<CacheWarmer> logger)
{
_cacheManager = cacheManager;
_logger = logger;
_warmupTasks = new List<CacheWarmupTask>();
}
public void RegisterWarmupTask<T>(string key, Func<Task<T>> factory, CacheOptions options = null)
{
_warmupTasks.Add(new CacheWarmupTask
{
Key = key,
Factory = async () => await factory(),
Options = options
});
}
public async Task WarmupAsync(CancellationToken cancellationToken = default)
{
_logger.LogInformation($"Starting cache warmup for {_warmupTasks.Count} tasks");
var semaphore = new SemaphoreSlim(Environment.ProcessorCount);
var tasks = _warmupTasks.Select(async task =>
{
await semaphore.WaitAsync(cancellationToken);
try
{
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
var value = await task.Factory();
await _cacheManager.SetAsync(task.Key, value, task.Options);
stopwatch.Stop();
_logger.LogDebug($"Warmed up cache key '{task.Key}' in {stopwatch.ElapsedMilliseconds}ms");
}
catch (Exception ex)
{
_logger.LogError(ex, $"Failed to warm up cache key '{task.Key}'");
}
finally
{
semaphore.Release();
}
});
await Task.WhenAll(tasks);
_logger.LogInformation("Cache warmup completed");
}
}
// 智能缓存策略
public class SmartCacheStrategy
{
private readonly ConcurrentDictionary<string, CacheAccessPattern> _accessPatterns;
private readonly Timer _analysisTimer;
public SmartCacheStrategy()
{
_accessPatterns = new ConcurrentDictionary<string, CacheAccessPattern>();
_analysisTimer = new Timer(AnalyzePatterns, null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
}
public void RecordAccess(string key)
{
_accessPatterns.AddOrUpdate(key,
new CacheAccessPattern { Key = key, AccessCount = 1, LastAccess = DateTime.UtcNow },
(k, existing) =>
{
existing.AccessCount++;
existing.LastAccess = DateTime.UtcNow;
return existing;
});
}
public CacheOptions GetOptimalOptions(string key)
{
if (_accessPatterns.TryGetValue(key, out var pattern))
{
// 基于访问模式调整缓存策略
var accessFrequency = pattern.AccessCount / (DateTime.UtcNow - pattern.FirstAccess).TotalHours;
if (accessFrequency > 10) // 高频访问
{
return new CacheOptions
{
MemoryExpiration = TimeSpan.FromMinutes(30),
DistributedExpiration = TimeSpan.FromHours(2)
};
}
else if (accessFrequency > 1) // 中频访问
{
return new CacheOptions
{
MemoryExpiration = TimeSpan.FromMinutes(10),
DistributedExpiration = TimeSpan.FromHours(1)
};
}
else // 低频访问
{
return new CacheOptions
{
MemoryExpiration = TimeSpan.FromMinutes(5),
DistributedExpiration = TimeSpan.FromMinutes(30)
};
}
}
return new CacheOptions(); // 默认选项
}
private void AnalyzePatterns(object state)
{
var now = DateTime.UtcNow;
var keysToRemove = new List<string>();
foreach (var kvp in _accessPatterns)
{
// 移除长时间未访问的模式记录
if (now - kvp.Value.LastAccess > TimeSpan.FromDays(7))
{
keysToRemove.Add(kvp.Key);
}
}
foreach (var key in keysToRemove)
{
_accessPatterns.TryRemove(key, out _);
}
}
public void Dispose()
{
_analysisTimer?.Dispose();
}
}
21.6 调试技术和工具
高级调试技术
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
// 调试信息收集器
public class DebugInfoCollector
{
private readonly ILogger<DebugInfoCollector> _logger;
private readonly List<DebugEvent> _events;
private readonly object _lock = new object();
public DebugInfoCollector(ILogger<DebugInfoCollector> logger)
{
_logger = logger;
_events = new List<DebugEvent>();
}
public void LogMethodEntry([CallerMemberName] string methodName = "",
[CallerFilePath] string filePath = "",
[CallerLineNumber] int lineNumber = 0,
params object[] parameters)
{
var debugEvent = new DebugEvent
{
Type = DebugEventType.MethodEntry,
Timestamp = DateTime.UtcNow,
MethodName = methodName,
FilePath = filePath,
LineNumber = lineNumber,
Parameters = parameters?.Select(p => p?.ToString()).ToArray(),
ThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId,
StackTrace = new StackTrace(1, true).ToString()
};
RecordEvent(debugEvent);
}
public void LogMethodExit([CallerMemberName] string methodName = "",
[CallerFilePath] string filePath = "",
[CallerLineNumber] int lineNumber = 0,
object returnValue = null)
{
var debugEvent = new DebugEvent
{
Type = DebugEventType.MethodExit,
Timestamp = DateTime.UtcNow,
MethodName = methodName,
FilePath = filePath,
LineNumber = lineNumber,
ReturnValue = returnValue?.ToString(),
ThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId
};
RecordEvent(debugEvent);
}
public void LogException(Exception exception,
[CallerMemberName] string methodName = "",
[CallerFilePath] string filePath = "",
[CallerLineNumber] int lineNumber = 0)
{
var debugEvent = new DebugEvent
{
Type = DebugEventType.Exception,
Timestamp = DateTime.UtcNow,
MethodName = methodName,
FilePath = filePath,
LineNumber = lineNumber,
Exception = exception,
ThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId,
StackTrace = exception.StackTrace
};
RecordEvent(debugEvent);
_logger.LogError(exception, $"Exception in {methodName} at {filePath}:{lineNumber}");
}
public void LogVariableState(string variableName, object value,
[CallerMemberName] string methodName = "",
[CallerFilePath] string filePath = "",
[CallerLineNumber] int lineNumber = 0)
{
var debugEvent = new DebugEvent
{
Type = DebugEventType.VariableState,
Timestamp = DateTime.UtcNow,
MethodName = methodName,
FilePath = filePath,
LineNumber = lineNumber,
VariableName = variableName,
VariableValue = SerializeObject(value),
ThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId
};
RecordEvent(debugEvent);
}
private void RecordEvent(DebugEvent debugEvent)
{
lock (_lock)
{
_events.Add(debugEvent);
// 限制事件数量,避免内存泄漏
if (_events.Count > 10000)
{
_events.RemoveRange(0, 1000);
}
}
}
private string SerializeObject(object obj)
{
if (obj == null) return "null";
try
{
// 简单序列化,避免循环引用
if (obj.GetType().IsPrimitive || obj is string || obj is DateTime)
{
return obj.ToString();
}
return System.Text.Json.JsonSerializer.Serialize(obj);
}
catch
{
return obj.ToString();
}
}
public DebugReport GenerateReport(TimeSpan? timeRange = null)
{
lock (_lock)
{
var events = _events.AsEnumerable();
if (timeRange.HasValue)
{
var cutoff = DateTime.UtcNow - timeRange.Value;
events = events.Where(e => e.Timestamp >= cutoff);
}
var eventList = events.ToList();
return new DebugReport
{
GeneratedAt = DateTime.UtcNow,
TimeRange = timeRange,
TotalEvents = eventList.Count,
Events = eventList,
ExceptionSummary = GenerateExceptionSummary(eventList),
MethodCallSummary = GenerateMethodCallSummary(eventList),
ThreadAnalysis = GenerateThreadAnalysis(eventList)
};
}
}
private List<ExceptionSummary> GenerateExceptionSummary(List<DebugEvent> events)
{
return events
.Where(e => e.Type == DebugEventType.Exception)
.GroupBy(e => e.Exception?.GetType().Name)
.Select(g => new ExceptionSummary
{
ExceptionType = g.Key,
Count = g.Count(),
LastOccurrence = g.Max(e => e.Timestamp),
CommonMethods = g.GroupBy(e => e.MethodName)
.OrderByDescending(mg => mg.Count())
.Take(5)
.Select(mg => mg.Key)
.ToList()
})
.OrderByDescending(s => s.Count)
.ToList();
}
private List<MethodCallSummary> GenerateMethodCallSummary(List<DebugEvent> events)
{
var methodEntries = events.Where(e => e.Type == DebugEventType.MethodEntry).ToList();
var methodExits = events.Where(e => e.Type == DebugEventType.MethodExit).ToList();
return methodEntries
.GroupBy(e => e.MethodName)
.Select(g => new MethodCallSummary
{
MethodName = g.Key,
CallCount = g.Count(),
AverageExecutionTime = CalculateAverageExecutionTime(g.ToList(), methodExits),
LastCalled = g.Max(e => e.Timestamp)
})
.OrderByDescending(s => s.CallCount)
.ToList();
}
private TimeSpan CalculateAverageExecutionTime(List<DebugEvent> entries, List<DebugEvent> exits)
{
var durations = new List<TimeSpan>();
foreach (var entry in entries)
{
var exit = exits.FirstOrDefault(e =>
e.MethodName == entry.MethodName &&
e.ThreadId == entry.ThreadId &&
e.Timestamp > entry.Timestamp);
if (exit != null)
{
durations.Add(exit.Timestamp - entry.Timestamp);
}
}
return durations.Any() ?
TimeSpan.FromTicks((long)durations.Average(d => d.Ticks)) :
TimeSpan.Zero;
}
private ThreadAnalysis GenerateThreadAnalysis(List<DebugEvent> events)
{
var threadGroups = events.GroupBy(e => e.ThreadId).ToList();
return new ThreadAnalysis
{
TotalThreads = threadGroups.Count,
ThreadDetails = threadGroups.Select(g => new ThreadDetail
{
ThreadId = g.Key,
EventCount = g.Count(),
FirstActivity = g.Min(e => e.Timestamp),
LastActivity = g.Max(e => e.Timestamp),
ExceptionCount = g.Count(e => e.Type == DebugEventType.Exception)
}).ToList()
};
}
public void ClearEvents()
{
lock (_lock)
{
_events.Clear();
}
}
}
// 性能分析装饰器
public class PerformanceProfiler
{
private readonly ConcurrentDictionary<string, MethodPerformanceData> _performanceData;
private readonly ILogger<PerformanceProfiler> _logger;
public PerformanceProfiler(ILogger<PerformanceProfiler> logger)
{
_logger = logger;
_performanceData = new ConcurrentDictionary<string, MethodPerformanceData>();
}
public async Task<T> ProfileAsync<T>(Func<Task<T>> method,
[CallerMemberName] string methodName = "")
{
var stopwatch = Stopwatch.StartNew();
var memoryBefore = GC.GetTotalMemory(false);
try
{
var result = await method();
stopwatch.Stop();
var memoryAfter = GC.GetTotalMemory(false);
RecordPerformance(methodName, stopwatch.Elapsed, memoryAfter - memoryBefore, true);
return result;
}
catch (Exception ex)
{
stopwatch.Stop();
var memoryAfter = GC.GetTotalMemory(false);
RecordPerformance(methodName, stopwatch.Elapsed, memoryAfter - memoryBefore, false);
_logger.LogError(ex, $"Method {methodName} failed after {stopwatch.ElapsedMilliseconds}ms");
throw;
}
}
public T Profile<T>(Func<T> method, [CallerMemberName] string methodName = "")
{
var stopwatch = Stopwatch.StartNew();
var memoryBefore = GC.GetTotalMemory(false);
try
{
var result = method();
stopwatch.Stop();
var memoryAfter = GC.GetTotalMemory(false);
RecordPerformance(methodName, stopwatch.Elapsed, memoryAfter - memoryBefore, true);
return result;
}
catch (Exception ex)
{
stopwatch.Stop();
var memoryAfter = GC.GetTotalMemory(false);
RecordPerformance(methodName, stopwatch.Elapsed, memoryAfter - memoryBefore, false);
_logger.LogError(ex, $"Method {methodName} failed after {stopwatch.ElapsedMilliseconds}ms");
throw;
}
}
private void RecordPerformance(string methodName, TimeSpan duration, long memoryDelta, bool success)
{
_performanceData.AddOrUpdate(methodName,
new MethodPerformanceData
{
MethodName = methodName,
CallCount = 1,
TotalDuration = duration,
MinDuration = duration,
MaxDuration = duration,
TotalMemoryDelta = memoryDelta,
SuccessCount = success ? 1 : 0
},
(key, existing) =>
{
existing.CallCount++;
existing.TotalDuration += duration;
existing.MinDuration = TimeSpan.FromTicks(Math.Min(existing.MinDuration.Ticks, duration.Ticks));
existing.MaxDuration = TimeSpan.FromTicks(Math.Max(existing.MaxDuration.Ticks, duration.Ticks));
existing.TotalMemoryDelta += memoryDelta;
if (success) existing.SuccessCount++;
return existing;
});
}
public PerformanceProfileReport GenerateReport()
{
var data = _performanceData.Values.ToList();
return new PerformanceProfileReport
{
GeneratedAt = DateTime.UtcNow,
TotalMethods = data.Count,
MethodPerformanceData = data.OrderByDescending(d => d.AverageDuration).ToList(),
TopSlowMethods = data.OrderByDescending(d => d.AverageDuration).Take(10).ToList(),
TopMemoryConsumers = data.OrderByDescending(d => d.AverageMemoryDelta).Take(10).ToList(),
MethodsWithErrors = data.Where(d => d.ErrorRate > 0).OrderByDescending(d => d.ErrorRate).ToList()
};
}
}
21.2 内存管理和垃圾回收优化
内存优化技术
using System;
using System.Buffers;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
// 对象池实现
public class ObjectPool<T> where T : class, new()
{
private readonly ConcurrentQueue<T> _objects = new ConcurrentQueue<T>();
private readonly Func<T> _objectGenerator;
private readonly Action<T> _resetAction;
private int _currentCount;
private readonly int _maxSize;
public ObjectPool(int maxSize = 100, Func<T> objectGenerator = null, Action<T> resetAction = null)
{
_maxSize = maxSize;
_objectGenerator = objectGenerator ?? (() => new T());
_resetAction = resetAction;
}
public T Get()
{
if (_objects.TryDequeue(out T item))
{
Interlocked.Decrement(ref _currentCount);
return item;
}
return _objectGenerator();
}
public void Return(T item)
{
if (item == null || _currentCount >= _maxSize)
return;
_resetAction?.Invoke(item);
_objects.Enqueue(item);
Interlocked.Increment(ref _currentCount);
}
public int Count => _currentCount;
}
// 内存高效的字符串构建器
public class MemoryEfficientStringBuilder : IDisposable
{
private readonly ArrayPool<char> _charPool;
private char[] _buffer;
private int _position;
private int _capacity;
public MemoryEfficientStringBuilder(int initialCapacity = 256)
{
_charPool = ArrayPool<char>.Shared;
_capacity = initialCapacity;
_buffer = _charPool.Rent(_capacity);
_position = 0;
}
public void Append(string value)
{
if (string.IsNullOrEmpty(value))
return;
EnsureCapacity(_position + value.Length);
value.AsSpan().CopyTo(_buffer.AsSpan(_position));
_position += value.Length;
}
public void Append(char value)
{
EnsureCapacity(_position + 1);
_buffer[_position++] = value;
}
public void Append(ReadOnlySpan<char> value)
{
EnsureCapacity(_position + value.Length);
value.CopyTo(_buffer.AsSpan(_position));
_position += value.Length;
}
private void EnsureCapacity(int requiredCapacity)
{
if (requiredCapacity <= _capacity)
return;
var newCapacity = Math.Max(requiredCapacity, _capacity * 2);
var newBuffer = _charPool.Rent(newCapacity);
_buffer.AsSpan(0, _position).CopyTo(newBuffer);
_charPool.Return(_buffer);
_buffer = newBuffer;
_capacity = newCapacity;
}
public override string ToString()
{
return new string(_buffer, 0, _position);
}
public void Clear()
{
_position = 0;
}
public void Dispose()
{
if (_buffer != null)
{
_charPool.Return(_buffer);
_buffer = null;
}
}
}
// 内存分析器
public class MemoryAnalyzer
{
public MemoryAnalysisResult AnalyzeMemoryUsage()
{
// 强制垃圾回收以获得准确的内存使用情况
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
var result = new MemoryAnalysisResult
{
AnalyzedAt = DateTime.UtcNow,
TotalMemory = GC.GetTotalMemory(false),
Gen0Collections = GC.CollectionCount(0),
Gen1Collections = GC.CollectionCount(1),
Gen2Collections = GC.CollectionCount(2)
};
// 分析各代内存
result.GenerationSizes = AnalyzeGenerationSizes();
// 分析大对象堆
result.LargeObjectHeapSize = AnalyzeLargeObjectHeap();
// 内存压力分析
result.MemoryPressure = AnalyzeMemoryPressure();
return result;
}
private Dictionary<int, long> AnalyzeGenerationSizes()
{
var sizes = new Dictionary<int, long>();
// 这是一个简化的实现,实际情况下可能需要使用更复杂的方法
// 来准确测量各代的大小
for (int generation = 0; generation <= 2; generation++)
{
var beforeCollection = GC.GetTotalMemory(false);
GC.Collect(generation, GCCollectionMode.Forced);
var afterCollection = GC.GetTotalMemory(false);
sizes[generation] = beforeCollection - afterCollection;
}
return sizes;
}
private long AnalyzeLargeObjectHeap()
{
// 大对象堆分析(简化实现)
var beforeLOH = GC.GetTotalMemory(false);
// 创建一个大对象来触发LOH
var largeArray = new byte[85000]; // 大于85KB的对象会进入LOH
var afterLOH = GC.GetTotalMemory(false);
// 清理测试对象
largeArray = null;
GC.Collect();
return afterLOH - beforeLOH;
}
private MemoryPressureLevel AnalyzeMemoryPressure()
{
var totalMemory = GC.GetTotalMemory(false);
var gen2Collections = GC.CollectionCount(2);
// 简化的内存压力评估
if (totalMemory > 500 * 1024 * 1024) // 超过500MB
{
return MemoryPressureLevel.High;
}
else if (totalMemory > 100 * 1024 * 1024) // 超过100MB
{
return MemoryPressureLevel.Medium;
}
else
{
return MemoryPressureLevel.Low;
}
}
public void OptimizeMemoryUsage()
{
// 强制垃圾回收
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
// 压缩大对象堆(.NET Core 2.0+)
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();
}
public MemoryLeakDetectionResult DetectMemoryLeaks(TimeSpan monitoringPeriod)
{
var initialMemory = GC.GetTotalMemory(true); // 强制GC后的内存
var initialTime = DateTime.UtcNow;
// 等待监控期间
System.Threading.Thread.Sleep(monitoringPeriod);
var finalMemory = GC.GetTotalMemory(true); // 强制GC后的内存
var finalTime = DateTime.UtcNow;
var memoryGrowth = finalMemory - initialMemory;
var growthRate = memoryGrowth / monitoringPeriod.TotalMinutes; // 每分钟增长
return new MemoryLeakDetectionResult
{
MonitoringPeriod = monitoringPeriod,
InitialMemory = initialMemory,
FinalMemory = finalMemory,
MemoryGrowth = memoryGrowth,
GrowthRatePerMinute = growthRate,
PotentialLeak = growthRate > 1024 * 1024, // 每分钟增长超过1MB认为可能有内存泄漏
LeakSeverity = DetermineLeakSeverity(growthRate)
};
}
private LeakSeverity DetermineLeakSeverity(double growthRatePerMinute)
{
if (growthRatePerMinute > 10 * 1024 * 1024) // 每分钟超过10MB
return LeakSeverity.Critical;
else if (growthRatePerMinute > 5 * 1024 * 1024) // 每分钟超过5MB
return LeakSeverity.High;
else if (growthRatePerMinute > 1 * 1024 * 1024) // 每分钟超过1MB
return LeakSeverity.Medium;
else
return LeakSeverity.Low;
}
}
// 弱引用缓存实现
public class WeakReferenceCache<TKey, TValue> where TValue : class
{
private readonly ConcurrentDictionary<TKey, WeakReference<TValue>> _cache;
private readonly Timer _cleanupTimer;
public WeakReferenceCache(TimeSpan cleanupInterval)
{
_cache = new ConcurrentDictionary<TKey, WeakReference<TValue>>();
_cleanupTimer = new Timer(Cleanup, null, cleanupInterval, cleanupInterval);
}
public void Set(TKey key, TValue value)
{
_cache.AddOrUpdate(key,
new WeakReference<TValue>(value),
(k, oldRef) => new WeakReference<TValue>(value));
}
public bool TryGet(TKey key, out TValue value)
{
value = null;
if (_cache.TryGetValue(key, out var weakRef) &&
weakRef.TryGetTarget(out value))
{
return true;
}
// 如果对象已被回收,移除弱引用
if (weakRef != null)
{
_cache.TryRemove(key, out _);
}
return false;
}
public void Remove(TKey key)
{
_cache.TryRemove(key, out _);
}
private void Cleanup(object state)
{
var keysToRemove = new List<TKey>();
foreach (var kvp in _cache)
{
if (!kvp.Value.TryGetTarget(out _))
{
keysToRemove.Add(kvp.Key);
}
}
foreach (var key in keysToRemove)
{
_cache.TryRemove(key, out _);
}
}
public int Count => _cache.Count;
public void Dispose()
{
_cleanupTimer?.Dispose();
_cache.Clear();
}
}
21.3 异步编程性能优化
异步性能优化技术
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
// 异步操作性能分析器
public class AsyncPerformanceAnalyzer
{
private readonly ConcurrentDictionary<string, AsyncOperationMetrics> _metrics;
private readonly ConcurrentQueue<AsyncOperationRecord> _records;
public AsyncPerformanceAnalyzer()
{
_metrics = new ConcurrentDictionary<string, AsyncOperationMetrics>();
_records = new ConcurrentQueue<AsyncOperationRecord>();
}
public async Task<T> MeasureAsync<T>(string operationName, Func<Task<T>> operation)
{
var record = new AsyncOperationRecord
{
OperationName = operationName,
StartTime = DateTime.UtcNow,
ThreadId = Thread.CurrentThread.ManagedThreadId
};
try
{
var result = await operation();
record.EndTime = DateTime.UtcNow;
record.Success = true;
record.CompletionThreadId = Thread.CurrentThread.ManagedThreadId;
UpdateMetrics(record);
_records.Enqueue(record);
return result;
}
catch (Exception ex)
{
record.EndTime = DateTime.UtcNow;
record.Success = false;
record.ErrorMessage = ex.Message;
record.CompletionThreadId = Thread.CurrentThread.ManagedThreadId;
UpdateMetrics(record);
_records.Enqueue(record);
throw;
}
}
private void UpdateMetrics(AsyncOperationRecord record)
{
_metrics.AddOrUpdate(record.OperationName,
new AsyncOperationMetrics
{
OperationName = record.OperationName,
TotalExecutions = 1,
SuccessfulExecutions = record.Success ? 1 : 0,
TotalExecutionTime = record.Duration,
MinExecutionTime = record.Duration,
MaxExecutionTime = record.Duration,
ThreadSwitches = record.ThreadId != record.CompletionThreadId ? 1 : 0
},
(key, existing) =>
{
existing.TotalExecutions++;
if (record.Success) existing.SuccessfulExecutions++;
existing.TotalExecutionTime += record.Duration;
existing.MinExecutionTime = TimeSpan.FromTicks(
Math.Min(existing.MinExecutionTime.Ticks, record.Duration.Ticks));
existing.MaxExecutionTime = TimeSpan.FromTicks(
Math.Max(existing.MaxExecutionTime.Ticks, record.Duration.Ticks));
if (record.ThreadId != record.CompletionThreadId)
existing.ThreadSwitches++;
return existing;
});
}
public AsyncPerformanceReport GenerateReport()
{
var report = new AsyncPerformanceReport
{
GeneratedAt = DateTime.UtcNow,
TotalOperations = _records.Count,
OperationMetrics = _metrics.Values.ToList()
};
// 分析线程池使用情况
report.ThreadPoolAnalysis = AnalyzeThreadPoolUsage();
// 识别异步反模式
report.AntiPatterns = IdentifyAsyncAntiPatterns();
return report;
}
private ThreadPoolAnalysis AnalyzeThreadPoolUsage()
{
ThreadPool.GetAvailableThreads(out int availableWorkerThreads, out int availableCompletionPortThreads);
ThreadPool.GetMaxThreads(out int maxWorkerThreads, out int maxCompletionPortThreads);
ThreadPool.GetMinThreads(out int minWorkerThreads, out int minCompletionPortThreads);
return new ThreadPoolAnalysis
{
MaxWorkerThreads = maxWorkerThreads,
AvailableWorkerThreads = availableWorkerThreads,
UsedWorkerThreads = maxWorkerThreads - availableWorkerThreads,
MaxCompletionPortThreads = maxCompletionPortThreads,
AvailableCompletionPortThreads = availableCompletionPortThreads,
UsedCompletionPortThreads = maxCompletionPortThreads - availableCompletionPortThreads,
ThreadPoolUtilization = (double)(maxWorkerThreads - availableWorkerThreads) / maxWorkerThreads * 100
};
}
private List<AsyncAntiPattern> IdentifyAsyncAntiPatterns()
{
var antiPatterns = new List<AsyncAntiPattern>();
// 检测频繁的线程切换
foreach (var metric in _metrics.Values)
{
var threadSwitchRate = (double)metric.ThreadSwitches / metric.TotalExecutions;
if (threadSwitchRate > 0.8) // 超过80%的操作发生线程切换
{
antiPatterns.Add(new AsyncAntiPattern
{
Type = AntiPatternType.ExcessiveThreadSwitching,
OperationName = metric.OperationName,
Description = $"Operation '{metric.OperationName}' has high thread switching rate: {threadSwitchRate:P}",
Severity = threadSwitchRate > 0.95 ? AntiPatternSeverity.High : AntiPatternSeverity.Medium
});
}
}
// 检测可能的同步等待
var recordsList = _records.ToList();
var suspiciousOperations = recordsList
.GroupBy(r => r.OperationName)
.Where(g => g.Average(r => r.Duration.TotalMilliseconds) > 1000 && // 平均执行时间超过1秒
g.All(r => r.ThreadId == r.CompletionThreadId)) // 没有线程切换
.Select(g => g.Key);
foreach (var operationName in suspiciousOperations)
{
antiPatterns.Add(new AsyncAntiPattern
{
Type = AntiPatternType.SynchronousWait,
OperationName = operationName,
Description = $"Operation '{operationName}' may be using synchronous wait (no thread switching detected)",
Severity = AntiPatternSeverity.Medium
});
}
return antiPatterns;
}
}
// 高性能异步批处理器
public class AsyncBatchProcessor<T>
{
private readonly Channel<T> _channel;
private readonly ChannelWriter<T> _writer;
private readonly ChannelReader<T> _reader;
private readonly Func<IEnumerable<T>, Task> _batchProcessor;
private readonly int _batchSize;
private readonly TimeSpan _batchTimeout;
private readonly CancellationTokenSource _cancellationTokenSource;
private readonly Task _processingTask;
public AsyncBatchProcessor(
Func<IEnumerable<T>, Task> batchProcessor,
int batchSize = 100,
TimeSpan? batchTimeout = null,
int capacity = 1000)
{
_batchProcessor = batchProcessor;
_batchSize = batchSize;
_batchTimeout = batchTimeout ?? TimeSpan.FromSeconds(5);
var options = new BoundedChannelOptions(capacity)
{
FullMode = BoundedChannelFullMode.Wait,
SingleReader = true,
SingleWriter = false
};
_channel = Channel.CreateBounded<T>(options);
_writer = _channel.Writer;
_reader = _channel.Reader;
_cancellationTokenSource = new CancellationTokenSource();
_processingTask = ProcessBatchesAsync(_cancellationTokenSource.Token);
}
public async Task AddAsync(T item, CancellationToken cancellationToken = default)
{
await _writer.WriteAsync(item, cancellationToken);
}
public bool TryAdd(T item)
{
return _writer.TryWrite(item);
}
private async Task ProcessBatchesAsync(CancellationToken cancellationToken)
{
var batch = new List<T>(_batchSize);
try
{
await foreach (var item in _reader.ReadAllAsync(cancellationToken))
{
batch.Add(item);
if (batch.Count >= _batchSize)
{
await ProcessBatchAsync(batch);
batch.Clear();
}
else
{
// 检查是否有更多项目可以立即处理
var timeoutTask = Task.Delay(_batchTimeout, cancellationToken);
var readTask = _reader.WaitToReadAsync(cancellationToken).AsTask();
var completedTask = await Task.WhenAny(timeoutTask, readTask);
if (completedTask == timeoutTask || !await readTask)
{
// 超时或没有更多项目,处理当前批次
if (batch.Count > 0)
{
await ProcessBatchAsync(batch);
batch.Clear();
}
}
}
}
// 处理剩余的项目
if (batch.Count > 0)
{
await ProcessBatchAsync(batch);
}
}
catch (OperationCanceledException)
{
// 正常取消
}
catch (Exception ex)
{
// 记录错误
Console.WriteLine($"Batch processing error: {ex.Message}");
}
}
private async Task ProcessBatchAsync(List<T> batch)
{
try
{
await _batchProcessor(batch);
}
catch (Exception ex)
{
// 记录批处理错误
Console.WriteLine($"Batch processing failed: {ex.Message}");
}
}
public async Task CompleteAsync()
{
_writer.Complete();
await _processingTask;
}
public void Dispose()
{
_writer.Complete();
_cancellationTokenSource.Cancel();
try
{
_processingTask.Wait(TimeSpan.FromSeconds(5));
}
catch (AggregateException)
{
// 忽略取消异常
}
_cancellationTokenSource.Dispose();
}
}
// 异步限流器
public class AsyncRateLimiter
{
private readonly SemaphoreSlim _semaphore;
private readonly Queue<DateTime> _requestTimes;
private readonly object _lock = new object();
private readonly int _maxRequests;
private readonly TimeSpan _timeWindow;
public AsyncRateLimiter(int maxRequests, TimeSpan timeWindow)
{
_maxRequests = maxRequests;
_timeWindow = timeWindow;
_semaphore = new SemaphoreSlim(maxRequests, maxRequests);
_requestTimes = new Queue<DateTime>();
}
public async Task<bool> TryAcquireAsync(CancellationToken cancellationToken = default)
{
var now = DateTime.UtcNow;
lock (_lock)
{
// 移除过期的请求时间
while (_requestTimes.Count > 0 && now - _requestTimes.Peek() > _timeWindow)
{
_requestTimes.Dequeue();
_semaphore.Release();
}
// 检查是否可以处理新请求
if (_requestTimes.Count < _maxRequests)
{
_requestTimes.Enqueue(now);
return true;
}
}
return false;
}
public async Task WaitAsync(CancellationToken cancellationToken = default)
{
while (!await TryAcquireAsync(cancellationToken))
{
// 计算需要等待的时间
var waitTime = TimeSpan.FromMilliseconds(100);
lock (_lock)
{
if (_requestTimes.Count > 0)
{
var oldestRequest = _requestTimes.Peek();
var timeUntilExpiry = _timeWindow - (DateTime.UtcNow - oldestRequest);
if (timeUntilExpiry > TimeSpan.Zero)
{
waitTime = timeUntilExpiry;
}
}
}
await Task.Delay(waitTime, cancellationToken);
}
}
public void Dispose()
{
_semaphore?.Dispose();
}
}
// 数据模型定义
public class PerformanceMetric
{
public string OperationName { get; set; }
public TimeSpan Duration { get; set; }
public DateTime Timestamp { get; set; }
public long MemoryBefore { get; set; }
public long MemoryAfter { get; set; }
public long MemoryAllocated { get; set; }
public bool Success { get; set; }
public string ErrorMessage { get; set; }
}
public class PerformanceReport
{
public DateTime GeneratedAt { get; set; }
public int TotalOperations { get; set; }
public int SuccessfulOperations { get; set; }
public int FailedOperations { get; set; }
public TimeSpan AverageExecutionTime { get; set; }
public TimeSpan MaxExecutionTime { get; set; }
public TimeSpan MinExecutionTime { get; set; }
public long TotalMemoryAllocated { get; set; }
public List<OperationStatistics> OperationStatistics { get; set; }
public List<PerformanceBottleneck> PerformanceBottlenecks { get; set; }
}
public class OperationStatistics
{
public string OperationName { get; set; }
public int Count { get; set; }
public TimeSpan AverageExecutionTime { get; set; }
public TimeSpan MaxExecutionTime { get; set; }
public TimeSpan MinExecutionTime { get; set; }
public long TotalMemoryAllocated { get; set; }
public double SuccessRate { get; set; }
}
public class PerformanceBottleneck
{
public BottleneckType Type { get; set; }
public string OperationName { get; set; }
public string Description { get; set; }
public TimeSpan AverageExecutionTime { get; set; }
public double AverageMemoryAllocation { get; set; }
public int Occurrences { get; set; }
public BottleneckSeverity Severity { get; set; }
}
public enum BottleneckType
{
SlowExecution,
HighMemoryUsage,
FrequentGarbageCollection,
ThreadContention
}
public enum BottleneckSeverity
{
Low,
Medium,
High,
Critical
}
public class SystemResourceSnapshot
{
public DateTime Timestamp { get; set; }
public float CpuUsagePercent { get; set; }
public float AvailableMemoryMB { get; set; }
public long ProcessMemoryMB { get; set; }
public long ProcessPrivateMemoryMB { get; set; }
public long ProcessVirtualMemoryMB { get; set; }
public int ThreadCount { get; set; }
public int HandleCount { get; set; }
public long GCTotalMemory { get; set; }
public int GCGen0Collections { get; set; }
public int GCGen1Collections { get; set; }
public int GCGen2Collections { get; set; }
}
public class ResourceAnalysisReport
{
public DateTime AnalyzedAt { get; set; }
public TimeSpan Duration { get; set; }
public int SnapshotCount { get; set; }
public double AverageCpuUsage { get; set; }
public double MaxCpuUsage { get; set; }
public double MinCpuUsage { get; set; }
public double AverageProcessMemory { get; set; }
public double MaxProcessMemory { get; set; }
public double MinProcessMemory { get; set; }
public double MemoryGrowth { get; set; }
public int TotalGCGen0Collections { get; set; }
public int TotalGCGen1Collections { get; set; }
public int TotalGCGen2Collections { get; set; }
public double AverageThreadCount { get; set; }
public int MaxThreadCount { get; set; }
public int MinThreadCount { get; set; }
public List<ResourceWarning> ResourceWarnings { get; set; }
}
public class ResourceWarning
{
public ResourceWarningType Type { get; set; }
public WarningSeverity Severity { get; set; }
public string Description { get; set; }
public double MaxValue { get; set; }
}
public enum ResourceWarningType
{
HighCpuUsage,
MemoryLeak,
FrequentGC,
ThreadPoolStarvation
}
public enum WarningSeverity
{
Info,
Warning,
Critical
}
public class MemoryAnalysisResult
{
public DateTime AnalyzedAt { get; set; }
public long TotalMemory { get; set; }
public int Gen0Collections { get; set; }
public int Gen1Collections { get; set; }
public int Gen2Collections { get; set; }
public Dictionary<int, long> GenerationSizes { get; set; }
public long LargeObjectHeapSize { get; set; }
public MemoryPressureLevel MemoryPressure { get; set; }
}
public enum MemoryPressureLevel
{
Low,
Medium,
High
}
public class MemoryLeakDetectionResult
{
public TimeSpan MonitoringPeriod { get; set; }
public long InitialMemory { get; set; }
public long FinalMemory { get; set; }
public long MemoryGrowth { get; set; }
public double GrowthRatePerMinute { get; set; }
public bool PotentialLeak { get; set; }
public LeakSeverity LeakSeverity { get; set; }
}
public enum LeakSeverity
{
Low,
Medium,
High,
Critical
}
public class AsyncOperationRecord
{
public string OperationName { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public TimeSpan Duration => EndTime - StartTime;
public bool Success { get; set; }
public string ErrorMessage { get; set; }
public int ThreadId { get; set; }
public int CompletionThreadId { get; set; }
}
public class AsyncOperationMetrics
{
public string OperationName { get; set; }
public int TotalExecutions { get; set; }
public int SuccessfulExecutions { get; set; }
public TimeSpan TotalExecutionTime { get; set; }
public TimeSpan MinExecutionTime { get; set; }
public TimeSpan MaxExecutionTime { get; set; }
public TimeSpan AverageExecutionTime =>
TotalExecutions > 0 ? TimeSpan.FromTicks(TotalExecutionTime.Ticks / TotalExecutions) : TimeSpan.Zero;
public int ThreadSwitches { get; set; }
public double SuccessRate => TotalExecutions > 0 ? (double)SuccessfulExecutions / TotalExecutions * 100 : 0;
}
public class AsyncPerformanceReport
{
public DateTime GeneratedAt { get; set; }
public int TotalOperations { get; set; }
public List<AsyncOperationMetrics> OperationMetrics { get; set; }
public ThreadPoolAnalysis ThreadPoolAnalysis { get; set; }
public List<AsyncAntiPattern> AntiPatterns { get; set; }
}
public class ThreadPoolAnalysis
{
public int MaxWorkerThreads { get; set; }
public int AvailableWorkerThreads { get; set; }
public int UsedWorkerThreads { get; set; }
public int MaxCompletionPortThreads { get; set; }
public int AvailableCompletionPortThreads { get; set; }
public int UsedCompletionPortThreads { get; set; }
public double ThreadPoolUtilization { get; set; }
}
public class AsyncAntiPattern
{
public AntiPatternType Type { get; set; }
public string OperationName { get; set; }
public string Description { get; set; }
public AntiPatternSeverity Severity { get; set; }
}
public enum AntiPatternType
{
ExcessiveThreadSwitching,
SynchronousWait,
TaskCreationOverhead,
ConfigureAwaitMissing
}
public enum AntiPatternSeverity
{
Low,
Medium,
High
}
21.4 数据库查询优化
查询性能分析和优化
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
// 数据库查询性能分析器
public class DatabaseQueryAnalyzer
{
private readonly ILogger<DatabaseQueryAnalyzer> _logger;
private readonly List<QueryPerformanceMetric> _metrics;
public DatabaseQueryAnalyzer(ILogger<DatabaseQueryAnalyzer> logger)
{
_logger = logger;
_metrics = new List<QueryPerformanceMetric>();
}
public async Task<T> MeasureQueryAsync<T>(string queryName, string sql,
Func<Task<T>> queryExecution, object parameters = null)
{
var stopwatch = Stopwatch.StartNew();
var startTime = DateTime.UtcNow;
try
{
var result = await queryExecution();
stopwatch.Stop();
var metric = new QueryPerformanceMetric
{
QueryName = queryName,
Sql = sql,
Parameters = parameters?.ToString(),
ExecutionTime = stopwatch.Elapsed,
StartTime = startTime,
Success = true,
RowsAffected = GetRowsAffected(result)
};
_metrics.Add(metric);
_logger.LogInformation($"Query '{queryName}' executed in {stopwatch.ElapsedMilliseconds}ms");
return result;
}
catch (Exception ex)
{
stopwatch.Stop();
var metric = new QueryPerformanceMetric
{
QueryName = queryName,
Sql = sql,
Parameters = parameters?.ToString(),
ExecutionTime = stopwatch.Elapsed,
StartTime = startTime,
Success = false,
ErrorMessage = ex.Message
};
_metrics.Add(metric);
_logger.LogError(ex, $"Query '{queryName}' failed after {stopwatch.ElapsedMilliseconds}ms");
throw;
}
}
private int GetRowsAffected<T>(T result)
{
if (result is IEnumerable<object> enumerable)
{
return enumerable.Count();
}
return result != null ? 1 : 0;
}
public QueryPerformanceReport GenerateReport()
{
var report = new QueryPerformanceReport
{
GeneratedAt = DateTime.UtcNow,
TotalQueries = _metrics.Count,
SuccessfulQueries = _metrics.Count(m => m.Success),
FailedQueries = _metrics.Count(m => !m.Success)
};
if (_metrics.Any())
{
report.AverageExecutionTime = TimeSpan.FromMilliseconds(
_metrics.Average(m => m.ExecutionTime.TotalMilliseconds));
report.MaxExecutionTime = _metrics.Max(m => m.ExecutionTime);
report.MinExecutionTime = _metrics.Min(m => m.ExecutionTime);
// 慢查询识别
var slowQueryThreshold = TimeSpan.FromSeconds(1);
report.SlowQueries = _metrics
.Where(m => m.ExecutionTime > slowQueryThreshold)
.OrderByDescending(m => m.ExecutionTime)
.Take(10)
.ToList();
// 查询统计
report.QueryStatistics = _metrics
.GroupBy(m => m.QueryName)
.Select(g => new QueryStatistics
{
QueryName = g.Key,
ExecutionCount = g.Count(),
AverageExecutionTime = TimeSpan.FromMilliseconds(
g.Average(m => m.ExecutionTime.TotalMilliseconds)),
MaxExecutionTime = g.Max(m => m.ExecutionTime),
MinExecutionTime = g.Min(m => m.ExecutionTime),
SuccessRate = (double)g.Count(m => m.Success) / g.Count() * 100,
TotalRowsAffected = g.Sum(m => m.RowsAffected)
})
.OrderByDescending(s => s.AverageExecutionTime)
.ToList();
// 性能建议
report.PerformanceRecommendations = GenerateRecommendations();
}
return report;
}
private List<PerformanceRecommendation> GenerateRecommendations()
{
var recommendations = new List<PerformanceRecommendation>();
// 识别N+1查询问题
var frequentQueries = _metrics
.GroupBy(m => m.QueryName)
.Where(g => g.Count() > 10 && g.Average(m => m.ExecutionTime.TotalMilliseconds) < 50)
.Select(g => g.Key);
foreach (var queryName in frequentQueries)
{
recommendations.Add(new PerformanceRecommendation
{
Type = RecommendationType.NPlusOneQuery,
QueryName = queryName,
Description = $"Query '{queryName}' executed frequently with short duration, possible N+1 query pattern",
Suggestion = "Consider using Include() or LoadMany() to reduce database round trips",
Priority = RecommendationPriority.High
});
}
// 识别缺少索引的查询
var slowQueries = _metrics
.Where(m => m.ExecutionTime.TotalSeconds > 1)
.GroupBy(m => m.QueryName)
.Where(g => g.Count() > 1);
foreach (var group in slowQueries)
{
recommendations.Add(new PerformanceRecommendation
{
Type = RecommendationType.MissingIndex,
QueryName = group.Key,
Description = $"Query '{group.Key}' consistently slow, may benefit from indexing",
Suggestion = "Analyze query execution plan and consider adding appropriate indexes",
Priority = RecommendationPriority.High
});
}
return recommendations;
}
}
// Entity Framework 性能优化器
public class EFPerformanceOptimizer
{
private readonly DbContext _context;
private readonly ILogger<EFPerformanceOptimizer> _logger;
public EFPerformanceOptimizer(DbContext context, ILogger<EFPerformanceOptimizer> logger)
{
_context = context;
_logger = logger;
}
// 批量操作优化
public async Task<int> BulkInsertAsync<T>(IEnumerable<T> entities, int batchSize = 1000)
where T : class
{
var totalInserted = 0;
var batch = new List<T>();
foreach (var entity in entities)
{
batch.Add(entity);
if (batch.Count >= batchSize)
{
await _context.Set<T>().AddRangeAsync(batch);
totalInserted += await _context.SaveChangesAsync();
batch.Clear();
_context.ChangeTracker.Clear(); // 清理变更跟踪器
}
}
// 处理剩余的实体
if (batch.Any())
{
await _context.Set<T>().AddRangeAsync(batch);
totalInserted += await _context.SaveChangesAsync();
}
return totalInserted;
}
public async Task<int> BulkUpdateAsync<T>(IEnumerable<T> entities, int batchSize = 1000)
where T : class
{
var totalUpdated = 0;
var batch = new List<T>();
foreach (var entity in entities)
{
batch.Add(entity);
if (batch.Count >= batchSize)
{
_context.Set<T>().UpdateRange(batch);
totalUpdated += await _context.SaveChangesAsync();
batch.Clear();
_context.ChangeTracker.Clear();
}
}
if (batch.Any())
{
_context.Set<T>().UpdateRange(batch);
totalUpdated += await _context.SaveChangesAsync();
}
return totalUpdated;
}
// 查询优化
public IQueryable<T> OptimizeQuery<T>(IQueryable<T> query, QueryOptimizationOptions options = null)
where T : class
{
options ??= new QueryOptimizationOptions();
// 禁用变更跟踪(只读查询)
if (options.AsNoTracking)
{
query = query.AsNoTracking();
}
// 拆分查询(避免笛卡尔积)
if (options.SplitQuery)
{
query = query.AsSplitQuery();
}
// 设置超时
if (options.CommandTimeout.HasValue)
{
_context.Database.SetCommandTimeout(options.CommandTimeout.Value);
}
return query;
}
// 预编译查询
public static readonly Func<DbContext, int, IAsyncEnumerable<User>> GetUsersByAgeCompiled =
EF.CompileAsyncQuery((DbContext context, int age) =>
context.Set<User>().Where(u => u.Age > age));
public static readonly Func<DbContext, string, Task<User>> GetUserByEmailCompiled =
EF.CompileAsyncQuery((DbContext context, string email) =>
context.Set<User>().FirstOrDefault(u => u.Email == email));
// 连接池优化
public async Task<T> ExecuteWithOptimizedConnectionAsync<T>(Func<Task<T>> operation)
{
// 确保连接被正确管理
using var transaction = await _context.Database.BeginTransactionAsync();
try
{
var result = await operation();
await transaction.CommitAsync();
return result;
}
catch
{
await transaction.RollbackAsync();
throw;
}
}
// 查询计划分析
public async Task<QueryExecutionPlan> AnalyzeQueryPlanAsync(string sql, object parameters = null)
{
var planSql = $"SET STATISTICS IO ON; SET STATISTICS TIME ON; {sql}";
using var command = _context.Database.GetDbConnection().CreateCommand();
command.CommandText = planSql;
if (parameters != null)
{
// 添加参数(简化实现)
foreach (var prop in parameters.GetType().GetProperties())
{
var parameter = command.CreateParameter();
parameter.ParameterName = $"@{prop.Name}";
parameter.Value = prop.GetValue(parameters) ?? DBNull.Value;
command.Parameters.Add(parameter);
}
}
await _context.Database.OpenConnectionAsync();
var stopwatch = Stopwatch.StartNew();
try
{
using var reader = await command.ExecuteReaderAsync();
var rowCount = 0;
while (await reader.ReadAsync())
{
rowCount++;
}
stopwatch.Stop();
return new QueryExecutionPlan
{
Sql = sql,
ExecutionTime = stopwatch.Elapsed,
RowCount = rowCount,
AnalyzedAt = DateTime.UtcNow
};
}
finally
{
await _context.Database.CloseConnectionAsync();
}
}
}
// 数据库连接池监控器
public class ConnectionPoolMonitor
{
private readonly string _connectionString;
private readonly ILogger<ConnectionPoolMonitor> _logger;
public ConnectionPoolMonitor(string connectionString, ILogger<ConnectionPoolMonitor> logger)
{
_connectionString = connectionString;
_logger = logger;
}
public async Task<ConnectionPoolStats> GetConnectionPoolStatsAsync()
{
var stats = new ConnectionPoolStats
{
Timestamp = DateTime.UtcNow
};
try
{
using var connection = new SqlConnection(_connectionString);
await connection.OpenAsync();
// 获取连接池统计信息
var poolStatsQuery = @"
SELECT
counter_name,
cntr_value
FROM sys.dm_os_performance_counters
WHERE object_name LIKE '%:General Statistics%'
OR object_name LIKE '%:Connection Pool%'
ORDER BY counter_name";
using var command = new SqlCommand(poolStatsQuery, connection);
using var reader = await command.ExecuteReaderAsync();
var counters = new Dictionary<string, long>();
while (await reader.ReadAsync())
{
var counterName = reader.GetString("counter_name");
var counterValue = reader.GetInt64("cntr_value");
counters[counterName] = counterValue;
}
// 解析统计信息
stats.ActiveConnections = counters.GetValueOrDefault("User Connections", 0);
stats.ConnectionsPerSecond = counters.GetValueOrDefault("Logins/sec", 0);
stats.DisconnectionsPerSecond = counters.GetValueOrDefault("Logouts/sec", 0);
// 测试连接性能
var connectionTestStopwatch = Stopwatch.StartNew();
using (var testConnection = new SqlConnection(_connectionString))
{
await testConnection.OpenAsync();
}
connectionTestStopwatch.Stop();
stats.ConnectionEstablishmentTime = connectionTestStopwatch.Elapsed;
stats.IsHealthy = connectionTestStopwatch.Elapsed < TimeSpan.FromSeconds(1);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to get connection pool statistics");
stats.IsHealthy = false;
stats.ErrorMessage = ex.Message;
}
return stats;
}
public async Task<List<ConnectionPoolStats>> MonitorAsync(TimeSpan duration, TimeSpan interval)
{
var stats = new List<ConnectionPoolStats>();
var endTime = DateTime.UtcNow.Add(duration);
while (DateTime.UtcNow < endTime)
{
var currentStats = await GetConnectionPoolStatsAsync();
stats.Add(currentStats);
await Task.Delay(interval);
}
return stats;
}
}
”`