向订阅者发送近期帖子邮件:外层循环选帖子还是订阅者?
问题
我的应用中存在PostSubscriber和Post两类实体:
public class PostSubscriber { public List<int> Topics { get; set; } ... } public class Post { public int Id { get; set; } ... }
每日运行的定时任务会获取近期帖子(通常少于30条)并推送给订阅者。规则为:若订阅者的Topics列表为空或null,则接收所有近期帖子通知;若Topics非空,则仅接收匹配帖子的通知。
当前实现为外层循环遍历帖子,每次迭代过滤出对应订阅者:
foreach(var post in posts) { var postSubscribers = preFetchedSubscribers.Where(i => i.Topics == null || !i.Topics.Any() || i.Topics.Contains(post.Id) ); ... }
我计划改为给每个订阅者发送一封包含所有匹配近期帖子的邮件,而非按帖子逐个发送。请问将外层循环改为遍历订阅者的实现:
foreach(var subscriber in subscribers) { foreach(var post in posts) { // 检查帖子是否匹配并拼接邮件内容 } ... // 发送拼接后的邮件 }
效率会更高还是更低?原因是什么?
分析与结论
效率更高,核心原因如下:
- 邮件发送次数大幅减少:邮件发送属于IO密集型操作,耗时远高于内存计算。当前实现按帖子逐个推送,假设30条帖子、1000个订阅者,即使单帖仅匹配100人,也会触发3000次发送;新实现每个订阅者仅发1封,只需1000次发送,这是性能提升的核心点。
- 循环计算开销差异可忽略:帖子数量固定少于30条,即使订阅者上千,总循环次数为「订阅者数×30」,和当前实现「帖子数×全量订阅者过滤」的计算量相比,差异极小。且新实现的匹配逻辑是简单内存操作,单次耗时可忽略。
- 优化空间更充足:新实现可提前将帖子ID存入
HashSet<int>,让Contains操作从O(n)降为O(1),进一步降低匹配开销;而当前实现每次过滤都要遍历全量订阅者,重复计算更多。
内容的提问来源于stack exchange,提问作者lexeme
相关产品推荐
相关产品推荐

