1

目标: 我试图估计我的代码在多个线程中同时运行时的执行速度。

问题1)

如果我确切地知道我的代码在一个线程中针对单个请求运行的速度有多快,那么他们有什么方法可以估计它在多个线程中的运行速度吗?

问题2)

如果有的话,其他线程的存在会影响其他线程的执行速度吗?

我的情况:

我遍历内存中最坏情况大小为 100 万个节点的图。它只是一次访问 100 万个内存地址 1。在 1 个线程上需要半秒钟,我担心这将如何随着多个用户执行相同的查询而扩展。每个用户请求都由一个单独的线程处理,因此 100 个并发用户将需要 100 个并发线程。每个线程共享相同的资源,但只读。没有写作。我有没有机会让每个用户看到大致相同的执行时间?

注意:我知道这将取决于许多因素,但如果您发现给定x 个硬件的单个线程需要x个时间,那么肯定有某种方法可以确定您的代码是否会扩展。作为最后一点,我想补充一点,我对计算机硬件架构以及多线程如何在后台工作的经验有限。

4

2 回答 2

4

这些都是有趣的问题,但不幸的是,没有直截了当的答案,因为答案取决于很多不同的因素。

大多数现代机器都是多核的:在理想情况下,四线程进程能够在四核机器中几乎线性扩展(即运行速度提高四倍)。

然而,大多数程序大部分时间都在等待:磁盘或数据库访问、内存总线、网络 I/O、用户输入和其他资源。更快的机器通常不会使这些事情变得更快。

大多数现代操作系统(包括 Windows、Unix/Linux 和 MacOS)使用处理器的方式是通过或多或少的循环方式将处理器时间调度给进程和线程:在任何给定时间都可能有线程正在等待处理器时间(这有点简单,因为它们都有一些进程优先级的概念,因此高关键性进程比不太重要的进程更早地被推入队列)。

当一个线程正在使用一个处理器内核时,只要它的时间片持续,它就会全部获取:实际上,一次只有一件事实际上在单个内核上运行。当进程用完它的时间片,或请求一些不能立即可用的资源时,它在处理器核心的轮次结束,下一个计划任务将开始。这往往会非常优化地利用处理器资源。

那么,决定流程扩大规模的因素是什么?

  • 单个进程在等待 I/O 和用户输入时花费了多少运行时间?

  • 多个线程访问相同的资源还是不同的资源?

  • 线程之间必须发生多少通信?在单个线程和您的进程主线程之间?这需要同步,并引入等待。

  • 活动线程的热点有多“紧”?它的主体可以放入处理器的内存中,还是必须访问(慢得多的)总线内存?

作为一般规则,独立线程彼此越独立,您的应用程序将越线性扩展。然而,在现实世界的商业应用程序中,情况远非如此。提高流程扩展能力的最好方法是理解它——以及它的依赖关系——然后使用分析器找出最等待的地方,看看你是否可以设计技术策略来避免它们。

于 2013-07-19T19:13:28.133 回答
2

如果我确切地知道我的代码在一个线程中针对单个请求运行的速度有多快,那么他们有什么方法可以估计它将在多个线程中运行的速度有多快?

不,您应该根据经验确定它。

如果有的话,其他线程的存在会影响其他线程的执行速度吗?

计算密集型任务可能会很好地扩展,并且大部分独立于其他线程。有趣的是,一些 CPU 制造商实现了一些功能,可以增加一个繁忙的 CPU 内核的时钟来补偿所有空闲的内核。这种功能可能会混淆您对缩放的测量和期望。

缓存/内存/磁盘绑定任务将开始相互竞争,除非存在资源分区。

我知道这将取决于许多因素

绝对地!因此,我建议您对其进行原型制作并进行测量。然后找出为什么它没有像你希望的那样扩展并尝试不同的算法。迭代。

但肯定有某种方法可以确定您的代码是否可以扩展

是的,但不幸的是,它需要对代码实现的算法进行详细描述。您的结果将在很大程度上取决于您的代码活动在这些一般区域中的比率,以及您的目标对这些区域的能力:

  • 磁盘 I/O
  • 网络 I/O
  • 内存输入/输出
  • 计算

我的情况:我的应用程序在一个应用服务器中运行,该服务器为每个用户请求分配一个线程。如果我的应用程序在 2 秒内为 1 个用户执行,我不能假设如果说 100 个用户同时运行相同的操作,它总是需要 2 秒,对吗?

如果您的应用服务器pi为每个用户请求计算到 100 位,那么它可能会很好地扩展,直到您遇到目标的核心限制。

如果您的应用服务器对每个用户请求进行数据库查询,它可能只会扩展,并且目标硬件可以承受必要的负载。

编辑给出的细节:

我遍历内存中最坏情况大小为 100 万个节点的图。它只是一次访问 100 万个内存地址 1。

你的问题听起来是内存+缓存绑定的。您应该研究目标 CPU/mem 部署的详细信息,或者如果您正在设计它,请选择高内存吞吐量。

  • NUMA 系统(内存的“资源分区”)可能会最大化您的整体并发内存吞吐量。请注意,由于您的问题似乎要求同时访问相同的内存页面,NUMA 系统会惩罚执行远程内存访问的进程。在这种情况下,请考虑在初始化时创建数据的多个副本。
  • 根据遍历的模式,TLB 压力可能是一个因素。考虑尝试使用巨大的(又名“大”)页面。
  • 缓存争用也可能是扩展的一个因素。
  • 您的特定算法很容易最终支配任何特定的系统效果,具体取决于最佳情况和最坏情况之间的距离。

对计算机硬件架构以及多线程如何在后台工作的经验有限。

使用 CPU 性能计数器和 Intel 的 VTuneperfoprofile. 它可以告诉您在代码中执行昂贵操作的位置。使用此信息,您可以优化查询以使其表现良好(单独和总体)。

于 2013-07-19T19:56:21.567 回答