

Also from Kynth Studios


Also from Kynth Studios


Also from Kynth Studios
1234567# 性能优化规范89## 异步编程10- **所有 I/O 操作必须使用异步方法**(`async/await`)11- **避免阻塞调用**:禁止使用 `Task.Result` 和 `Task.Wait()`12- **高频调用优化**:使用 `ValueTask<T>` 减少堆分配13- **避免异步循环**:使用批量处理代替循环中的异步操作1415### 正确示例16```csharp17// ✅ 正确:使用异步方法18public async Task<List<QuestionDto>> GetQuestionsAsync(QuestionQueryDto query)19{20 var entities = await _repository.GetListAsync(query);21 return _mapper.Map<List<QuestionDto>>(entities);22}2324// ✅ 正确:批量处理25public async Task<List<QuestionDto>> GetQuestionsByIdsAsync(List<long> ids)26{27 // 一次查询获取所有数据28 var entities = await _dbContext.Questions29 .Where(q => ids.Contains(q.Id))30 .ToListAsync();31 return _mapper.Map<List<QuestionDto>>(entities);32}33```3435### 错误示例36```csharp37// ❌ 错误:阻塞调用38public List<QuestionDto> GetQuestions(QuestionQueryDto query)39{40 var entities = _repository.GetListAsync(query).Result; // 阻塞!41 return _mapper.Map<List<QuestionDto>>(entities);42}4344// ❌ 错误:异步循环45public async Task<List<QuestionDto>> GetQuestionsByIdsAsync(List<long> ids)46{47 var results = new List<QuestionDto>();48 foreach (var id in ids)49 {50 var entity = await _repository.GetByIdAsync(id); // N 次查询!51 results.Add(_mapper.Map<QuestionDto>(entity));52 }53 return results;54}55```5657## 缓存策略5859### 缓存键命名60```csharp61// 格式:{service}:{entity}:{identifier}62"exam:question:123"63"exam:questions:list:categoryId_5"64"exam:user:profile:456"6566// 租户缓存:{tenantId}:{service}:{entity}:{identifier}67"tenant_1:exam:question:123"68```6970### 缓存级别71- **L1 (内存缓存)**:频繁访问的小数据(配置、枚举等)72- **L2 (Redis)**:需要跨实例共享的数据73- **L1AndL2**:热点数据(如用户信息、权限数据)7475### 使用示例76```csharp77public class QuestionService78{79 private readonly ICacheService _cacheService;8081 public async Task<QuestionDto> GetByIdAsync(long id)82 {83 return await _cacheService.GetOrSetAsync(84 $"exam:question:{id}",85 async () => await _repository.GetByIdAsync(id),86 new CacheOptions87 {88 AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30),89 Level = CacheLevel.L1AndL290 });91 }9293 public async Task UpdateAsync(long id, UpdateQuestionDto dto)94 {95 await _repository.UpdateAsync(id, dto);9697 // 更新后清除缓存98 await _cacheService.RemoveAsync($"exam:question:{id}");99 }100}101```102103### 过期策略104- **静态数据**:绝对过期时间(1小时以上)105- **动态数据**:滑动过期时间(5-30分钟)106- **实时数据**:不缓存或短期缓存(1-5分钟)107108## EF Core 查询优化109110### 1. AsNoTracking 只读查询111```csharp112// ✅ 只读查询使用 AsNoTracking113public async Task<List<QuestionDto>> GetListAsync(QuestionQueryDto query)114{115 var entities = await _dbContext.Questions116 .AsNoTracking() // 不跟踪实体变化,提升性能117 .Where(q => q.IsDeleted == false)118 .ToListAsync();119 return _mapper.Map<List<QuestionDto>>(entities);120}121```122123### 2. Include 避免 N+1 查询124```csharp125// ✅ 正确:一次查询加载关联数据126public async Task<List<QuestionDto>> GetListWithCategoryAsync()127{128 var entities = await _dbContext.Questions129 .Include(q => q.Category) // 预加载关联数据130 .AsNoTracking()131 .ToListAsync();132 return _mapper.Map<List<QuestionDto>>(entities);133}134135// ❌ 错误:N+1 查询136public async Task<List<QuestionDto>> GetListWithCategoryAsync()137{138 var entities = await _dbContext.Questions.ToListAsync();139 foreach (var entity in entities)140 {141 entity.Category = await _dbContext.Categories.FindAsync(entity.CategoryId); // N次查询!142 }143 return _mapper.Map<List<QuestionDto>>(entities);144}145```146147### 3. AsSplitQuery 处理笛卡尔积148```csharp149// ✅ 多对多关联使用 AsSplitQuery150public async Task<ExamDto> GetExamWithQuestionsAsync(long examId)151{152 var exam = await _dbContext.Exams153 .Include(e => e.Questions)154 .ThenInclude(q => q.Options)155 .AsSplitQuery() // 拆分为多个查询,避免笛卡尔积156 .FirstOrDefaultAsync(e => e.Id == examId);157 return _mapper.Map<ExamDto>(exam);158}159```160161### 4. 批量操作162```csharp163// ✅ 批量更新(EF Core 7+)164public async Task UpdateScoresAsync(Dictionary<long, decimal> scores)165{166 await _dbContext.Questions167 .Where(q => scores.Keys.Contains(q.Id))168 .ExecuteUpdateAsync(setters => setters169 .SetProperty(q => q.Score, q => scores[q.Id]));170}171172// ✅ 批量删除(EF Core 7+)173public async Task DeleteByCategoryAsync(long categoryId)174{175 await _dbContext.Questions176 .Where(q => q.CategoryId == categoryId)177 .ExecuteDeleteAsync();178}179```180181### 5. 投影查询182```csharp183// ✅ 只查询需要的字段184public async Task<List<QuestionListItemDto>> GetListAsync()185{186 return await _dbContext.Questions187 .Select(q => new QuestionListItemDto188 {189 Id = q.Id,190 Content = q.Content,191 CategoryName = q.Category.Name192 })193 .ToListAsync();194}195```196197## 分布式场景优化198199### 1. 分布式锁200```csharp201public async Task<bool> TryStartExamAsync(long examId, long userId)202{203 var lockKey = $"exam:start:{examId}:{userId}";204205 await using var lockHandle = await _distributedLock.TryAcquireAsync(206 lockKey,207 TimeSpan.FromSeconds(10));208209 if (lockHandle == null)210 {211 throw new BusinessException("Errors.ExamAlreadyStarted");212 }213214 // 执行业务逻辑215 await _examService.StartExamAsync(examId, userId);216 return true;217}218```219220### 2. 分布式缓存221```csharp222public async Task<UserDto> GetUserAsync(long userId)223{224 return await _cacheService.GetOrSetAsync(225 $"user:{userId}",226 async () => await _userRepository.GetByIdAsync(userId),227 new CacheOptions228 {229 Level = CacheLevel.L2 // Redis 分布式缓存230 });231}232```233234### 3. 事件驱动解耦235```csharp236// 发布事件237public async Task CreateOrderAsync(CreateOrderDto dto)238{239 var order = await _orderRepository.CreateAsync(dto);240241 // 发布事件,异步处理后续逻辑242 await _eventBus.PublishAsync(new OrderCreatedEvent243 {244 OrderId = order.Id,245 UserId = order.UserId246 });247}248249// 订阅事件250public class OrderCreatedEventHandler : IEventHandler<OrderCreatedEvent>251{252 public async Task HandleAsync(OrderCreatedEvent @event)253 {254 // 异步处理:发送通知、更新库存等255 await _notificationService.NotifyOrderCreatedAsync(@event.OrderId);256 }257}258```259260### 4. 最终一致性261```csharp262// 避免分布式事务,采用最终一致性263public async Task CreateOrderAsync(CreateOrderDto dto)264{265 // 1. 先创建订单(主业务)266 var order = await _orderRepository.CreateAsync(dto);267268 // 2. 发布事件,异步处理库存扣减269 await _eventBus.PublishAsync(new OrderCreatedEvent270 {271 OrderId = order.Id,272 Items = dto.Items273 });274275 // 库存扣减失败时,通过补偿机制处理276}277```278279## 数据库连接池280- 使用连接池管理数据库连接281- 避免长时间占用连接282- 及时释放连接(使用 `using` 或 DI 容器管理)283284## 注意事项285- 定期监控性能指标(响应时间、吞吐量、资源使用)286- 使用 Application Insights 或类似工具进行性能分析287- 避免过早优化,先测量后优化288- 考虑分布式场景下的数据一致性289- 缓存要考虑缓存穿透、雪崩、击穿等问题290
One repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| xin-lai/CodeSpirit.cursor/rules/api-design.mdc · 56 | Cursor rules | no sections | 54/100 | 14 days ago | |
| xin-lai/CodeSpirit.cursor/rules/controller.mdc · 56 | Cursor rules | api | 54/100 | 14 days ago | |
| xin-lai/CodeSpirit.cursor/rules/dependency-injection.mdc · 56 | Cursor rules | api | 54/100 | 14 days ago | |
| xin-lai/CodeSpirit.cursor/rules/dto.mdc · 56 | Cursor rules | no sections | 50/100 | 14 days ago | |
| xin-lai/CodeSpirit.cursor/rules/js.mdc · 56 | Cursor rules | apidocs | 46/100 | 14 days ago | |
| xin-lai/CodeSpirit.cursor/rules/security.mdc · 56 | Cursor rules | database | 54/100 | 14 days ago | |
| xin-lai/CodeSpirit.cursor/rules/service.mdc · 56 | Cursor rules | no sections | 50/100 | 14 days ago | |
| xin-lai/CodeSpiritAGENTS.md · 56 | AGENTS.md | styleagent-behaviourdocs | 66/100 | 14 days ago | |
| xin-lai/CodeSpirit.cursor/rules/ai-development.mdc · 56 | Cursor rules | api | 46/100 | 14 days ago | |
| xin-lai/CodeSpirit.cursor/rules/amis-cards.mdc · 56 | Cursor rules | no sections | 54/100 | 14 days ago | |
| xin-lai/CodeSpirit.cursor/rules/csproj.mdc · 56 | Cursor rules | api | 54/100 | 14 days ago | |
| xin-lai/CodeSpirit.cursor/rules/database.mdc · 56 | Cursor rules | no sections | 74/100 | 14 days ago | |
| xin-lai/CodeSpirit.cursor/rules/naming-conventions.mdc · 56 | Cursor rules | no sections | 50/100 | 14 days ago | |
| xin-lai/CodeSpirit.cursor/rules/package-management.mdc · 56 | Cursor rules | no sections | 74/100 | 14 days ago | |
| xin-lai/CodeSpirit.cursor/rules/project-structure.mdc · 56 | Cursor rules | api | 54/100 | 14 days ago | |
| xin-lai/CodeSpirit.cursor/rules/testing.mdc · 56 | Cursor rules | testing-strategy | 54/100 | 14 days ago | |
| xin-lai/CodeSpirit.cursor/rules/cs.mdc · 56 | Cursor rules | no sections | 25/100 | 14 days ago | |
| xin-lai/CodeSpirit.cursor/rules/all.mdc · 56 | Cursor rules | testing-strategyapi | 50/100 | 14 days ago | |
| xin-lai/CodeSpirit.cursor/rules/css.mdc · 56 | Cursor rules | ui | 54/100 | 14 days ago | |
| xin-lai/CodeSpirit.cursor/rules/enum.mdc · 56 | Cursor rules | no sections | 50/100 | 14 days ago |
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| hiromaily/go-crypto-wallet.cursor/rules/typescript.mdc · 126 | Cursor rules | setupbuildtestlint-format+6 | 100/100 | 14 days ago | |
| TechSquidTV/Hermes.cursor/rules/10-hermes-api.mdc · 46 | Cursor rules | testlint-formatstylearch+5 | 100/100 | 14 days ago | |
| dodgecfr/combatfilms-webapp.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 14 days ago | |
| deifos/clipmira-subtitles.cursor/rules/frontend.mdc · 1 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 14 days ago | |
| markstev/mark-starter.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+6 | 99/100 | 14 days ago | |
| Allymahmoud/case-intake-platform.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 14 days ago | |
| langflow-ai/langflow.cursor/rules/docs_development.mdc · 153k | Cursor rules | setupbuildtestlint-format+7 | 97/100 | 14 days ago | |
| TechSquidTV/Hermes.cursor/rules/20-hermes-api-tests.mdc · 46 | Cursor rules | teststyletesting-strategysecurity+3 | 97/100 | 14 days ago |
A badge carrying the measured quality of the strongest agent config file in this repository, out of 100. It reads from this index every time somebody loads your page, so it changes when the measurement changes and there is nothing to keep up to date. Free, no account, and the value is not something you or we can set by hand.
[](https://rulestack.kynth.studio/configs/xin-lai-codespirit-cursor-rules-performance)Would rather not hotlink us? Every badge is also served in shields.io’s endpoint schema, so shields renders the image and your readers never talk to our domain:
Published by Toolproof, the masthead over this index and eight others. The method behind the number is at toolproof.kynth.studio/methodology, and the whole thing is readable as JSON with no key at /api.