我有一个控制台应用程序(c#),我必须在其中调用各种第三方 API 并收集数据。这我必须同时为不同的用户做。我正在使用线程。但是随着用户数量的增加,这项服务正在消耗 CPU 性能。它正在影响其他进程。有没有办法我们可以使用线程进行并行处理,但不会对 CPU 性能产生很大影响。
2 回答
我从您的问题中假设您正在手动创建线程,因此回答这个问题的快速方法是建议您使用像Task Parallel Library这样的 API ,因为这将执行任意数量的任务并尝试使用合理的处理它们的线程数 - 因此给定 500 个 API 请求,它会将自身限制为仅几个线程。
但是,要更详细地回答:您会看到此问题的典型原因是代码创建了太多线程。线程不是免费资源——它们很昂贵。
根据您的问题编写的示例可能是这样的:
- 您有 5 个需要调用的第 3 方 API,每个 API 将为每位用户返回约 1MB 的数据
- 您为每个用户在单独的后台线程上调用每个 API
- 你有 100 个用户
- 因此,您总共创建了 500 个线程,每个线程都在等待来自网络的数据
这里的问题是程序试图管理 500 个线程,它们都在等待系统中最慢的部分——网络。
更简单地说,我们试图一次下载 500 条数据(在这个例子中,这意味着一切都完成得很慢),而不是一次下载一个,这样单个项目就会更早完成。因为每个线程都不会做任何事情(只是等待网络),CPU 会不断在空闲线程之间切换。随着用户数量的增加,线程数量也会增加——这会增加 CPU 使用率,仅用于线程之间的切换,即使每个线程实际上下载速度更慢。这就是(大约)为什么随着用户数量的增加,您会看到性能变慢的原因。
一个更好的例子是采用相同的场景并仅使用一个后台线程:
- 您有 5 个需要调用的第 3 方 API,每个 API 将为每位用户返回约 1MB 的数据
- 每个 API 调用都放入一个队列中,该队列由单个线程处理
- 你有 100 个用户
- 因此,您有 1 个线程在后台运行,该线程为每个请求使用网络的全部可用带宽
在这个示例中,您的 CPU 使用率将非常一致 - 无论您有多少用户,只有一个后台线程在运行,因此上下文切换被最小化。每个单独的 API 调用都以网卡的最大速率运行,因此会尽快完成。
现实情况是,一个线程可能还不够:单个请求不太可能使网络饱和,因为其他地方会有限制因素。但这是您以后可以调整的:也许 2 或 3 个线程会更高性能,但 4 个线程会再次变慢。线程处理的一般规则是从小处着手,而不是为每件工作创建一个线程。