是否有任何指导方针可以了解特定程序是否会受益于多线程?
在单线程中,CPU利用率通常较低,如果程序的不相关部分被分成单独的线程,则在某些情况下可能会更高。也许当一个线程在等待I / O时,其他线程可以利用CPU。但是在程序中需要注意什么才能看出它是否会从多线程中受益?
答案 0 :(得分:2)
通常,当您可以在多个独立子任务中分解任务并且您实际上有多个处理器来执行任务(优化)时,或者如果您需要保持系统“交互”(即使是阻塞任务,例如,正在执行从网络读取,其他线程可以继续处理用户请求。
另一个原因是模拟paralelism(即使你没有像线程一样多的处理器)同时执行几个“任务”(即使没有实现真正的优化)。这就是操作系统的简单操作,它们会在并行中运行多个程序,即使它们必须给它们很少的时间来执行它们。
答案 1 :(得分:2)
要使用多线程,您必须具有可以同时执行的独立任务。这些需要是非繁琐的,理想情况下至少需要10微秒,否则使用多个线程的开销可能高于使用多个线程的优势。
如果您的进程是IO绑定的,即使您只有一个核心,它也可以从使用多个线程中受益。如果您的进程受CPU限制,则必须使用可用内核来提高性能。
CPU绑定进程可以拥有的最大改进等于核心数。即如果你有N个核心,它可以快上N倍。这假设您至少可以执行N个独立任务。
通常优化代码可以使您的应用程序快速发展,而不会发生重大变化。通过更改代码,我所做的最大改进比以前的实现要好1000倍。出于这个原因,您的第一步应该是剖析和分析您的系统,看看它是否可以改进。之后考虑多线程化您的应用程序。
将工作传递给另一个线程并非易事,尤其是如果您传递的是少量大型任务。队列可以处理高吞吐量,但如果您想在最短的时间内完成任务,则延迟很重要。
这是在适度的2.3 GHz T4500上运行的。传递的数据量是微不足道的,当您在线程之间访问更多数据时,所需的时间就越长。
ExecutorService es = Executors.newCachedThreadPool();
for(int i=0;i<20;i++) {
Thread.sleep(10);
Future<Long> future = es.submit(new Callable<Long>() {
long start = System.nanoTime();
public Long call() throws Exception {
return start;
}
});
System.out.printf("Took %.1f us to submit/get%n",
(System.nanoTime() - future.get())/1e3);
}
es.shutdown();
打印
Took 61.1 us to submit/get
Took 45.1 us to submit/get
Took 49.1 us to submit/get
Took 37.9 us to submit/get
Took 58.5 us to submit/get
答案 2 :(得分:1)
由于Muli-Core CPU的性质,目前大多数情况下的程序都会受益于多线程。单个线程一次只能在一个核心上工作,而多个线程可以分布在多个核心上。
更重要的问题是:什么时候可以多线程?哪些任务可以并行化?通常这是不可能的,有时甚至不需要,因为它为您的代码引入了一个非常难以调试的不可预测的元素:竞争条件。
是的,如果你的程序在I / O上等待很多,那么你的CPU在这段时间里经常处于空闲状态。如果在此期间你可以用CPU做任何事情,那么它会自然地提高性能;-)。即使是单核心。
另一个更新:还要记住,可以过度使用多线程。如果你有比运行的CPU核心更多的线程,那么你的调度程序将不得不在这些线程之间切换,这是一些开销。如果你的线程没有阻塞(I / O或其他东西),那么这个开销只是浪费时间。
答案 3 :(得分:1)
多线程通常通常是一个好主意,因为您可以利用多核的功能。现代CPU通常不会获得更快的内核但是内核更多,因此如果它是多线程的,您的应用程序将从中受益。
如前所述,艰巨的任务是使多线程正确。在大多数情况下,您应该专门为多线程设计应用程序。如果您有一个单线程应用程序并希望加快速度,那么您可能会寻找可能被分成多个部分的冗长操作(例如,查找每个迭代独立于其他部分的循环)。
但是,请记住,多线程也会产生一些开销,因此单个任务需要一定的miminal大小才能生效。
答案 4 :(得分:1)
请注意其他海报提供的答案,我将在其中添加一些:
1)必须处理需要超时和/或延迟的多个操作的应用程序。多线程可以消除复杂且难以调试的状态机(一个线程实际上是由OS运行的状态机)。明显的例子是需要延迟实现特定协议的多通道通信应用程序 - sleep()比所有定时器,回调等等更容易实现,理解和调试,而不是感染需要此功能的单线程应用程序。为每个通道运行单独的线程允许这样的代码“在线”写入。一旦你有一个频道工作,100没问题。
2)需要阻止API的应用。有一些API,(好吧,无论如何,在Windows上),阻止并没有异步替代,特别是。在旧操作系统上。没有专门的线程来调用它们,你就会陷入困境。
3)多线程解决方案看起来更快的应用程序,但提供的成本/性能优势不足以使其值得一试。明年,事情会有所不同。
4)作为大型系统一部分且打印要求规格大于~100g的应用程序,开始考虑多个线程。
5)如果应用程序是微不足道的,没有时间限制,你很少/没有线程体验,无论如何都要关闭它的一部分,只是为了它的乐趣(?)。过了一段时间,您将只知道如何构建大型复杂的应用程序,以便它们可靠地运行并且可维护和可扩展。 “我不做多线程”在接受采访中不顺利:)
RGDS, 马丁