9

想象一下,我有两个(三个、四个,等等)必须并行运行的任务。现在,执行此操作的简单方法是创建单独的线程并忘记它。但是在一个普通的老式单核 CPU 上,这意味着很多上下文切换——我们都知道上下文切换很大、很糟糕、很慢,而且通常只是邪恶的。应该避免吧?

在那一点上,如果我是从头开始编写软件,我可以加倍努力并实现我自己的任务切换。将每个任务分成几部分,保存中间的状态,然后在单个线程中切换它们。或者,如果我检测到有多个 CPU 内核,我可以将每个任务分配给一个单独的线程,一切都会好起来的。

第二种解决方案确实具有适应可用 CPU 内核数量的优势,但是手动任务切换真的会比 OS 内核中的更快吗?特别是如果我试图用 aTaskManager和 anITask等使整个事情通用?

澄清:我是一名 Windows 开发人员,所以我主要对这个操作系统的答案感兴趣,但最有趣的是找出其他操作系统。当您写下您的答案时,请说明它适用于哪个操作系统。

更多说明:好的,所以这不是在特定应用程序的上下文中。这确实是一个普遍的问题,是我对可扩展性的思考的结果。如果我希望我的应用程序能够扩展并有效地利用未来的 CPU(甚至是今天的不同 CPU),我必须让它成为多线程的。但是有多少线程?如果我创建恒定数量的线程,那么程序将在所有内核数不同的 CPU 上执行次优。

理想情况下,线程数将在运行时确定,但很少有任务可以在运行时真正拆分为任意数量的部分。然而,许多任务可以在设计时拆分为相当大的恒定数量的线程。因此,例如,如果我的程序可以产生 32 个线程,那么它已经使用了多达 32 核 CPU 的所有内核,这在未来还很遥远(我认为)。但是在一个简单的单核或双核 CPU 上,这将意味着大量的上下文切换,这会减慢速度。

因此,我对手动任务切换的想法。这样一来,可以创建 32 个“虚拟”线程,这些线程将映射到尽可能多的真实线程,并且“上下文切换”将手动完成。问题只是 - 我的手动“上下文切换”的开销会小于操作系统上下文切换的开销吗?

自然,所有这些都适用于受 CPU 限制的进程,例如游戏。对于您的普通 CRUD 应用程序,这几乎没有价值。这样的应用程序最好使用一个线程(最多两个)。

4

3 回答 3

6

我看不出手动任务切换如何更快,因为操作系统内核仍在切换其他进程,包括您的进程也退出运行状态。似乎是过早的优化和潜在的巨大努力浪费。

如果系统没有做任何其他事情,那么您很可能不会有大量的上下文切换。线程将使用它的时间片,内核调度程序将看到没有其他需要运行并立即切换回您的线程。此外,操作系统将尽最大努力避免在 CPU 之间移动线程,因此您可以从缓存中受益。

如果您真的受 CPU 限制,请检测 CPU 的数量并启动那么多线程。您应该会看到几乎 100% 的 CPU 利用率。如果没有,您还没有完全受 CPU 限制,也许答案是启动 N + X 个线程。对于非常 IO 绑定的进程,您将启动 CPU 计数的(大)倍数(即高流量网络服务器运行 1000 多个线程)。

最后,作为参考,Windows 和 Linux 调度程序都每毫秒唤醒一次,以检查是否需要运行另一个进程。因此,即使在空闲系统上,您也会看到每秒 1000 多次上下文切换。在负载较重的系统上,我看到每个 CPU 每秒处理超过 10,000 次,没有任何重大问题。

于 2010-05-12T18:13:14.160 回答
5

我可以看到手动切换的唯一优点是您可以更好地控制切换发生的地点和时间。理想的地方当然是一个工作单元完成之后,这样你就可以把它全部扔掉。这可以为您节省缓存未命中。

我建议不要在这上面花费你的精力。

于 2010-05-08T16:09:12.960 回答
3

单核 Windows 机器将在未来几年内灭绝,所以我通常会假设多核是常见的情况来编写新代码。我想说的是操作系统线程管理,它会自动处理硬件提供的任何并发性,现在和将来。

我不知道您的应用程序做了什么,但除非您有多个计算密集型任务,否则我怀疑上下文切换是大多数应用程序中的一个重要瓶颈。如果您的任务在 I/O 上阻塞,那么您将不会从尝试超越操作系统中获得太多好处。

于 2010-05-08T15:51:50.900 回答