【问题标题】:Is Multithreading in Java I/O bound (or) CPU boundJava I/O 中的多线程是否受(或)CPU 限制
【发布时间】:2015-04-04 04:33:58
【问题描述】:

我已经开始学习多核编程和开发并行算法。这可以通过在 Java 中使用多线程轻松完成。于是,我创建了两个文本文件,10行内容如下:

This is the first line in file 1
This is the second line in file 1
This is the third line in file 1 
This is the fourth line in file 1
This is the fifth line in file 1
This is the sixth line in file 1
This is the seventh line in file 1
This is the eighth line in file 1
This is the ninth line in file 1
This is the tenth line in file 1

同样,在另一个文本文件中,文件 1 被替换为 文件 2。我写了一个程序来读取文件的内容,有和没有线程。它们如下:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

public class SimpleThread {

    static void printFile(BufferedReader br) throws Exception
    {
        for(String line; (line = br.readLine())!=null; )
            System.out.println(line);
    }

    public static void main(String args[]) throws Exception
    {
        double startTime = System.nanoTime();
        BufferedReader br1 = new BufferedReader(new FileReader(new File("test1.txt")));
        BufferedReader br2 = new BufferedReader(new FileReader(new File("test2.txt")));
        SimpleThread.printFile(br1);
        SimpleThread.printFile(br2);
        System.out.println(System.nanoTime() - startTime + "ns");
    }
}

使用多线程的程序如下:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

public class Threading extends Thread{

    BufferedReader br;

    public Threading(String fileName)
    {
        try{
        br = new BufferedReader(new FileReader(new File(fileName)));
        start();
        }
        catch(Exception e)
        {
            System.out.println(e.getMessage());
        }
    }

    private void printFile(BufferedReader br) throws Exception
    {
        for(String line; (line = br.readLine())!=null; )
            System.out.println(line);
    }

    public void run()
    {
        try{
        printFile(br);
        }
        catch(Exception e)
        {
            System.out.println(e.getMessage());
        }
    }

    public static void main(String args[]) throws Exception
    {
        double startTime = System.nanoTime();
        Threading t1 = new Threading("test1.txt");
        Threading t2 = new Threading("test2.txt");
        System.out.println(System.nanoTime() - startTime + "ns");
    }
}

现在,当我比较两个程序的执行时间时,我发现单线程程序需要 1544589.0ns,而多线程程序需要 410522.0ns

我很想知道提高速度的因素。我发现它大约是 0.23

修改了使用多线程的代码后,发现单线程程序执行速度更快,这在更大程度上增加了我的困惑。

这是修改后的代码:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

public class Threading extends Thread{

    BufferedReader br;

    public Threading(String fileName)
    {
        try{
        br = new BufferedReader(new FileReader(new File(fileName)));
        start();
        }
        catch(Exception e)
        {
            System.out.println(e.getMessage());
        }
    }

    private void printFile(BufferedReader br) throws Exception
    {
        for(String line; (line = br.readLine())!=null; )
            System.out.println(line);
    }

    public void run()
    {
        try{
        printFile(br);
        }
        catch(Exception e)
        {
            System.out.println(e.getMessage());
        }
    }

    public static void main(String args[]) throws Exception
    {
        double startTime = System.nanoTime();
        Threading t1 = new Threading("test1.txt");
        Threading t2 = new Threading("test2.txt");
        t1.join(); //waiting for t1 to finish
        t2.join(); //waiting for t2 to finish
        System.out.println(System.nanoTime() - startTime + "ns");
    }
}

现在执行时间是: 单线程 - 1459052.0ns
多线程 - 1768651.0ns

为什么系统的行为不自然?

现在,我的问题是:

  1. 会增加线程数,减少执行时间吗?
  2. 何时应该在编写程序时使用多线程
  3. 是否可以将相同的文件概念移植到数据库中,每个线程根据类别读取数据库的一部分,例如新闻、体育、政治等信息将由相应的线程读取,最终结果将被捆绑在一起。这可行吗?
  4. 是否应该仅将多线程用于 CPU 密集型程序?

【问题讨论】:

  • 您的多线程程序不会等到工作线程完成其工作后才报告运行时。
  • 视情况而定,有很多优点和缺点,所以我认为你应该阅读一些关于多线程的书。

标签: java multithreading


【解决方案1】:

我很想知道提高速度的因素。我发现它大约是 0.23。

那是因为你的多线程测试无效。它实际上并没有测量线程所花费的时间。相反,它只是测量启动线程的时间。

其他测试也无效。您没有考虑 JVM 预热效应……而且测试所做的工作量不足以作为指示。

另一个问题是读取文件所花费的时间(例如在 Linux 上)取决于操作系统是否已经缓存了它。因此,如果您运行其中一项测试,然后再次运行,您很可能会发现第二次运行速度明显加快!

现在执行时间是:单线程 - 1459052.0ns 多线程 - 1768651.0ns

为什么系统的行为不自然?

这实际上是我期望会发生的事情......对于那个版本的基准。由于使用两个线程进行读取,创建两个线程的开销似乎超过任何(假设的)加速。


您的问题:

第一季度。增加线程数会减少执行时间吗?

可能会。这取决于您拥有多少内核、线程是 CPU 还是 I/O 绑定、是否存在数据结构或资源争用等。

第二季度。什么时候应该在编写程序时使用多线程

当关注性能时,可以将问题合理地划分为可以并行执行的子任务。此外,对于小问题,设置线程的开销可能超过任何可能的性能提升。

第三季度。是否可以将相同的文件概念移植到数据库中,其中每个线程根据类别读取数据库的一部分,例如新闻,体育,政治等信息将由相应的线程读取,最后将结果组合在一起.这可行吗?

也许吧。

但是,您的(无效)测试可能会让您对多线程的好处产生误导。实际上,任何涉及读取或写入磁盘的操作都受到磁盘驱动器具有单个读/写“头”并且一次只能执行一个硬件级别的读取或写入操作这一事实的限制。操作系统或数据库系统可以使用各种技巧来给人以更快性能的印象,但如果应用程序足够努力,你就会碰壁。

简而言之,理论上可能只有有限的加速。

第四季度。多线程应该只用于 CPU 密集型程序吗?

没有。

但这并不意味着多线程应该用于所有事情。

它甚至不应该用于所有 CPU 密集型程序!

简单的概括不适用。这要复杂得多。

【讨论】:

  • 非常感谢您的回答。我很满意,除了一件事。如何测量多线程环境中的执行时间(或)查看性能?
  • 只有当它确实存在时,您才能看到加速。在这种情况下,我的直觉是不应该有任何加速。当然不是在像这个一样小的基准测试中。
  • 但是如果你问如何编写一个 valid 基准来衡量加速如果它确实存在 ...你应该从阅读 stackoverflow.com/questions/504103 开始,它解释了人们在 Java 基准测试中所犯的常见错误以及如何避免这些错误。
【解决方案2】:

线程是一个有助于并行执行的概念。很多时候我们看到CPU是空闲的,它的处理速度远远超过人类或者小代码sn-ps。当我们引入线程时,我们试图通过确保它有足够多的指令集来执行来减少 CPU 的空闲时间。

举个例子;

在每笔交易中,在我们真正进入核心业务逻辑(由 CPU 执行)之前,我们确实需要遵循一些前后基本步骤。在这些活动期间,CPU 处于空闲状态。通过多线程,我们确保在一个线程实际正在处理的同时,另一个线程的 pre/post 活动也同时执行,因此一旦第一个任务的处理结束,第二个任务就可以进行处理。

关于你的下一个问题,我们应该为基本功能而不是核心业务逻辑实现多线程,因为它可能会产生不利影响。

如果可能,我们总是尝试为代价高昂的活动(需要更多时间)引入并行执行。

【讨论】:

    猜你喜欢
    • 2011-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-10
    • 1970-01-01
    • 1970-01-01
    • 2013-02-05
    • 1970-01-01
    相关资源
    最近更新 更多