Windows,多进程 vs 多线程

5
我们需要使我们的系统高度可扩展,它是使用VC++在Windows平台上开发的。假设最初我们想要同时处理100个请求(来自msmq),最佳方法是什么?使用单个进程和100个线程还是2个进程和50-50个线程?除了进程内存之外,在第二种方法中有什么收益?在Windows中,首先将CPU时间分配给进程,然后再根据进程中的线程数量进行分割,还是操作系统根据线程而不是进程的数量来分配CPU时间。我们注意到,在第一种情况下,CPU利用率为15-25%,我们希望消耗更多的CPU。请记住,我们希望获得最佳性能,因此100个请求只是一个例子。我们还注意到,如果将进程的线程数增加到120以上,性能会因上下文切换而降低。
还有一点,我们的产品已经支持集群,但我们想在单个节点上利用更多的CPU。
非常感谢您提供任何建议。
2个回答

5
您不能处理比CPU核心更多的请求。 "快速"可伸缩的解决方案涉及设置线程池,其中活动(未被阻塞在IO上)线程的数量== CPU核心的数量。因此,仅因为要处理100个msmq请求而创建100个线程并不是好的设计。

Windows具有称为IO完成端口的线程池机制。

使用IO完成端口将设计推向单个进程,因为在多进程设计中,每个进程都将拥有其自己的IO完成端口线程池,并且将独立管理它,因此您可能会得到更多的线程争用CPU核心。

IO完成端口的“核心”思想是它是一个内核模式队列-您可以手动将事件发布到队列中,或者通过将文件(文件、套接字、管道)句柄与端口关联来自动将异步IO完成发布到该队列中。

另一方面,IO完成端口机制会自动将事件出队到等待的工作线程-但是如果检测到当前“活动”线程在线程池中的数量> = CPU核心的数量,则不会出队作业。

使用IO完成端口可以潜在地大大增加服务的可伸缩性,但通常情况下,收益要比预期小得多,因为当所有CPU核心争用服务的其他资源时,其他因素很快就会发挥作用。

如果您的服务是使用c ++开发的,则可能会发现对堆的序列化访问是一个重大的性能问题-尽管Windows版本6.1似乎已经实现了低争用堆,因此这可能不是一个问题。

总之-理论上,您最大的性能提升将来自使用在单个进程中管理的线程池的设计。但是,您严重依赖于您使用的库不会对关键资源进行序列化访问,否则这可能会迅速失去所有理论性能提升。

如果您确实有库代码序列化您的良好线程池服务(例如由于堆争用而序列化的c ++对象创建和销毁),则需要更改您对库的使用/切换到库的低争用版本或仅扩展到多个进程。

唯一的方法是编写压力测试服务器的测试用例并测量结果。


我一定会编写测试用例。但我想知道Windows理论上如何进行CPU调度。这可以帮助我分析测试。 - Mubashir Khan
只是再多补充一点,我们正在使用VS2008,我猜它使用的是6.1 SDK。我该如何确认这一点呢? - Mubashir Khan
无论您使用哪个版本的SDK进行开发,只要您升级服务器,“Windows 7”堆(即Windows版本6.1)的性能增益就会自动生效。 - Chris Becke
这篇由Mark Russinovich撰写的文章可能会让你了解NT如何实现IO完成端口。http://doc.sch130.nsc.ru/www.sysinternals.com/ntw2k/info/comport.shtml - Chris Becke

3
在Windows上,标准方法是使用多线程。并不是说这总是最好的解决方案,但每个线程或进程都有一个代价,在Windows上,进程的代价更高。至于调度程序,我不确定,但您可以设置进程和线程的优先级。线程的真正好处在于它们共享地址空间,并且可以在没有IPC的情况下进行通信,但必须小心地维护同步。
如果您的系统已经开发完成,那么实现多进程解决方案可能会更容易,特别是如果以后有可能使用多台机器。因为在一台机器上的2个进程之间的IPC可以在一般情况下扩展到多台机器。大规模并行化的大多数尝试都失败了,因为整个系统没有被评估出瓶颈。例如,如果您实现了100个写入同一数据库的线程,您可能在实际性能上获得很少的提升,只会等待数据库。
以上仅为个人见解。

1
是的,我们已经面临过这个问题。数据库是主要瓶颈。不想冒犯任何人,但与SQL Server相比,我们在使用Oracle时性能要好得多。但在我们的地区,大多数客户都坚持使用SQL Server(因为价格更便宜),因此对我们来说是一个真正的瓶颈。 - Mubashir Khan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接