阅读The Complete Friday Q&A:Volume I第一天
关于多线程编程和并行方式有以下几种方式:
1、分布式计算。对于Mac开发人员来说,最明显的例子是Xcode中的分布式构建。对于开发者来说费时费力,因此最没有用处。与您在单台计算机上获得的带宽和延迟相比,计算机之间的带宽和延迟微乎其微,因此很难通过编程来提升运行速度。 Xcode可以避免使用它,因为它(通常)会对它处理的每一位数据进行大量处理。除了获得速度上的困难外,您还必须应对更容易出错的环境。如果用户徘徊在wifi范围之外,您希望从容恢复,而不丢失大量数据。在大多数情况下,这样做是不值得的,特别是如果您要交付消费级软件。
2、GPGPU-通用图形处理器。基本上使用视频卡进行计算。这就是GPULife所做的。它具有巨大的力量。如果使用正确的程序,则顶级视频卡可以轻松胜过顶级CPU的50倍。这同样很难实现。 GPU高度并行化,并且具有与CPU截然不同的体系结构,因此很难对其进行编码,而使其快速运行则更加困难。 (尽管由于可用的功能强大,即使很慢的GPU代码也可以非常快地运行。)诸如CUDA和OpenCL之类的技术有望使这种事情变得更好,尽管您总是要面对这样一个事实:具有完全不同的性能特征的大规模并行系统。我在这里的建议是等待Snow Leopard,然后希望OpenCL兑现诺言。
3、多进程。同样,Xcode是此方法的一个突出示例,您可以看到它在编译时产生了多个gcc实例。与OS相比,这通常被认为是一种比多线程更容易,更安全的方法,因为OS可以保护进程之间的相互影响,并可以更好地分离问题。我个人不这样认为。对于几乎所有不平凡的程序,一个死子进程将意味着整个程序崩溃,而将其拆分为多个进程所做的所有事情都使得调试变得更加困难。更糟糕的是,操作系统对进程数量的限制往往非常之低,因此您的程序将需要妥善处理无法产生所需数量的子进程。 (以及系统上的所有其他应用程序也将需要!)
4、多线程。标准技术。通常很难正确使用,也很难调试,但是就性能而言可能非常有意义。线程还可以帮助更好地组织程序。将长时间运行的处理或阻塞操作放到一个单独的线程中通常比将它们多路复用在一起要干净得多。
多线程是我们最熟悉的一种,也是最有用的一种。它非常通用,因此很有用,因此您可以使用多种方式使用多线程来实际完成工作:
锁。 “标准”多线程。您具有受锁保护的共享数据。在修改数据之前先获取锁。通常用于制造更复杂的系统。达到这个级别可能很困难,因此我建议您尽可能避免使用它,并在需要的地方尽量少使用它来构建更好的抽象。
消息传递。通过消息传递,您可以避免共享数据,并让线程使用消息队列进行通信。 (消息队列内部通常共享数据,但这是一个实现细节。)Cocoa通过-performSelectorOnMainThread:...和performSelector:onThread:...调用为此提供了一些不错的功能。重线程语言Erlang广泛使用此模型,是其多线程功能背后的主要力量。
操作单元。这有点像消息传递,只是操作只是飞走并在使用视图外线程的队列上执行。当设置为一次仅执行一个操作时,队列就可以充当同步点,以通常更易于使用的方式替换锁。 NSOperationQueue提供了此功能,并且有传言称,雪豹的Grand Central Dispatch将提供类似的功能。
原子/交易对象。您可以构建使用事务进行操作的对象,而不是使用互斥(锁定,队列)来避免破坏共享数据。抓取快照,进行更改,然后提交。 (通常这是作为一个循环实现的:快照,更改,尝试提交并在中间发生某些更改时尝试使用新快照重新开始。)TransactionKit是可可上下文中此类事件的一个很好的例子。
关于使用什么,这是我的想法。除非您的代码将由具有大量可用硬件的单个客户端运行,否则请避免使用分布式计算。能够通过闲置在用户家中的硬件来减少CPU周期听起来很酷,但大部分时间并没有得到回报。除非您有非常好的应用程序,否则在Mac上避免使用GPGPU,直到Snow Leopard出货为止。 OpenCL将使GPGPU更加实用和灵活,因此,今天尝试将计算量大的代码插入GLSL或CoreImage中似乎并不值得.
如果已经编写了子程序,则使用多个进程是一个好主意。如果将gcc作为子进程调用,则在四个文件上而不是一个一个地同时调用它是很容易的。如果您是从头开始编写代码,除非您有其他充分的理由来编写子流程,否则我不建议您这样做,因为这很困难,而且回报还不存在。
对于多线程,请专注于消息传递和操作。多线程从来都不是一件容易的事,但是它们可以极大地简化和减少错误。好的OO设计在这里也会有很大帮助。对已经被分解为具有明确定义的接口以及它们之间的松散耦合的简单对象的应用程序进行多线程处理要容易得多。