您现在的位置: 中国教师站 >> 教师关注 >> 电脑技术 >> 编程技术 >> Visual C >> 正文

Google
Win32 多线程的性能
作者:Siny 文章来源:中国教师站cn-teacher 点击数: 更新时间:2007-4-22 12:45:25
Win32 多线程的性能

Ruediger R. Asche
Microsoft Developer Network 技术小组

摘要

本文讨论将单线程应用程序重新编写成多线程应用程序的策略。它以Microsoft Windows 95和Windows NT的平台为例,从吞吐量(throughput)和响应方面,与兼容的单线程计算相比较而分析了多线程计算的性能。

介绍

在您所能够找到的有关多线程的资料中,多数都是讲述同步概念的。例如,如何串行化(serialize)共享公共数据的线程。这种把重点放在讨论同步上是有意义的,因为同步是多线程编程中不可缺少的一部分。本文则后退了一步(takes a step back),主要讨论有关多线程中很少有人涉及的一面:决定一个计算如何能够被有意义地拆分为多个线程。本文中所使用的示例程序,THRDPERF,在Microsoft Windows 95和Windows NT 两个平台之上,针对同一个计算采取串行和并发两种方法分别实现了测试套件(test suite),并从吞吐量和性能两方面来比较它们。

本文的第一部分建立了一些有关多线程应用程序的词汇(vocabulary),讨论测试套件的范围,并且介绍了示例程序套件是如何设计的。第二部分讨论测试的结果,并且包括对于多线程应用程序设计的建议。与之相关的文章 "Interacting with Microsoft Excel: A Case Study in OLE Automation" 讨论有关该示例程序套件的一个有趣的问题,即使用测试集合所获得的数据是如何使用 OLE Automation被输入 Microsoft Excel 中的。

如果您是经验丰富的多线程应用程序编程者,您可以跳过介绍部分,而直接到下面的"结果"部分。

多线程词汇

很长一段时间以来,您的应用程序一直被使用--它运转出色,是可以信赖的,而且 the whole bit--但它十分的迟缓,并且您有如何利用多线程的想法。但是,在开始这样做之前请稍等一会儿,因为这里有许多的陷阱,它们使您相信某种多线程设计是非常完美的,但实际上并不是这样。

在您跳至有关要进入的结论之前,首先让我们澄清一下在本文中将不讨论的内容:

  • 在 Microsoft Win32 应用程序编程接口(API)下提供多线程访问的库是不同的,但是我们不关注这一问题。示例程序套件,Threadlib.exe,是在一个Microsoft Foundation Class Library (MFC)应用程序中使用Win32多线程API来编写的,但是,您是使用Microsoft C运行时(CRT)库、MFC库,还是单纯的(barebones) Win32 API来创建和维持线程,我们并不关心。

    实际上,每一种库最后都要调用 Win32 系统服务CreateThread来创建一个工作线程,并且多线程本身总是要通过操作系统来执行。您想要使用哪一种包装机制将不会影响本文的论题。当然,您是使用某一个还是使用其它的包装库(wrapper library),可能会引起性能上的差异,但是在这儿,我们主要讨论多线程的本质,而不关心其包装(wrapper)。

  • 本文所讨论的是在单处理器机器上运行的多线程应用程序。多处理器计算机则是一个完全不同的主题,并且本文中所讨论的结论,几乎没有一个可以应用于多处理器的机器中。我还没有这样的机会在一个运行 Windows NT 系统的可调整的(scalable)对称多线程(SMP)机器上执行该示例。如果您有这样的机会,我非常高兴地希望知道您的结果。

  • 在本文中,我更喜欢一般性地引用"计算"。计算被定义为您的应用程序的一个子任务,可以被作为整体或部分来执行,可以早于或迟于另一个计算,或者与其他的计算同时发生。例如,让我们假设某个应用程序需要用户的数据,并且需要保存这些数据到磁盘。我们可以假定输入数据包含一种计算,而保存这些数据则是另一种计算。根据应用程序的计算的设计,下面两种情况都是可能的:一种是数据的保存和新数据的输入是同时交叉进行的;另一种是直到用户已经输入了全部的数据才可是将数据保存到磁盘上。第一种情况一般可以使用某种形式的多线程来实现;我们称这种组织计算的方式为并发或交互。后一种情况一般可以用单线程应用程序来实现,在本文中,它被称为串行执行。

  • 有关并发应用程序的设计是一个非常复杂的过程。一般非常有钱的(who make a ton of money)人比较喜欢它,因为要计算出一个给定的任务采用并发执行到底有多大的好处,通常需要多年的研究。本文并不想要教您如何设计多线程应用程序。相反,我要向您指出某些多线程应用程序设计的问题所在,而且,我使用真实(real-life)的性能测试来讨论我的例子。在阅读过本文后,您应该能够观察一个给定的设计,并且能够决定某种设计是否提高了该应用程序的整体性能。

  • 多线程应用程序设计步骤中的一部分工作,就是要决定在何处存在可能潜在地引起数据毁坏的多线程数据访问冲突,以及如何使用线程的同步来避免这种冲突。这项任务(以后,本文将称之为线程编序(thread serialization))是许多有关多线程的文章的主题,(例如,MSDN Library中的 "Synchronization on the Fly"或"Compound Win32 Synchronization Objects"),在本文中将丝毫不涉及对它的讨论。有关在本文中要讨论的,我们将假定需要并发的计算并不共享任何数据,并且因此而不需要任何线程编序。这种约定看起来可能有点苛刻,但是请您牢记,不可能有关于同步多线程应用程序的"通用"的讨论,因为每一次编序都将强加一个唯一的"等待-醒来"结构(waiting-and-waking pattern)到已编序的线程,它将直接地影响性能。

  • Win32下的大多数输入/输出(I/O)操作有两种形态:同步或异步。已经被证明在许多的情况下,一个使用同步I/O的多线程设计可以被使用异步单线程I/O的设计来模拟。本文并不讨论作为多线程替代形式的异步单线程I/O,但是,我建议您最好两种设计都考虑。

    注意到Win32 I/O系统设计的方式是提供一些机制,使得异步I/O要优于同步I/O(例如,I/O全能端口(completion ports))。我计划在以后的文章中讨论有关同步I/O和异步I/O的问题。

  • 正如在"Multiple Threads in the User Interface"一文中所指出的,多线程和图形用户界面(GUI)不能很好地共同工作。在本文中,我假设后台线程可以执行其工作而根本不需要使用Windows GUI;我所处理的这种类型的线程仅仅是"工作线程",它仅在后台执行计算,而不需要与用户的直接交互。

  • 有有限计算,同样也有与之相对应的无限计算。服务器端应用程序中的一个"倾听"线程就是无限计算的一个例子,它没有任何的目的,只是等待一个客户连接到服务器。在一个客户已经连接之后,该线程就发送一个通知到主线程,并且返回到"倾听"状态,直到下一个客户的连接。很自然,这样的一种计算不可能驻留在同一个作为应用程序用户界面(UI)的线程之中,除非使用一种异步I/O操作。(请注意,这个特定的问题能够,也应该通过使用异步I/O和全能(completion)端口来解决,而不是使用多线程,我在这里使用这个例子仅仅是用作演示)。在本文中,我将只考虑有限计算,就是说,应用程序的子任务将在有限的时间段之后结束。

基于CPU的计算和基于I/O的计算

对于一个单个的线程,决定所给定的计算是否是一个优秀的方案的最重要因素是,该计算是一个基于CPU的计算还是基于I/O的计算。基于CPU的计算是指这种计算的大多数时间CPU都非常"忙"。典型的基于CPU的计算如下:

    [1] [2] [3] [4] [5] [6] [7] [8] 下一页

相关专题:
 
 网友评论:(评论内容只代表网友观点,与本站立场无关!)
GOOGLE广告

阅读排行

| 设为首页 | 加入收藏 | 联系站长 | 友情链接 | 版权申明 |
中国教师站

中国教师站 版权所有 Copyright © 2006-2020 All Rights Reserved 站长:Sina & Siny
[备用域名:www.JXZYW.Com] 有事请留言有事请留言
【实力成就精品 诚信呵护品牌】

信息产业部备案
苏ICP备06018635号