2013-07-30 133 views
0

我想完成一个我已经完成的任务,除了这次使用多线程。我必须从文件中读取大量数据(逐行),从每行中获取一些信息,然后将其添加到Map中。该文件超过一百万行,所以我认为它可能会受益于多线程。如何使用多线程来有效地使用多线程

我不确定我的方法,因为我从来没有在Java中使用过多线程。 我想让主要方法进行读取,然后将已读取的行赋予另一个将格式化String的线程,然后将其传递给另一个线程以放入地图。

public static void main(String[] args) 
{ 
    //Some information read from file 
    BufferedReader br = null; 
    String line = ''; 
    try { 
     br = new BufferedReader(new FileReader("somefile.txt")); 
     while((line = br.readLine()) != null) { 
      // Pass line to another task 
     } 


    // Here I want to get a total from B, but I'm not sure how to go about doing that 

} 


public class Parser extends Thread 
{ 
    private Mapper m1; 

    // Some reference to B 
    public Parse (Mapper m) { 
     m1 = m; 
    } 

    public parse (String s, int i) { 
     // Do some work on S 
     key = DoSomethingWithString(s); 
     m1.add(key, i); 
    } 

} 

public class Mapper extends Thread 
{ 
    private SortedMap<String, Integer> sm; 
    private String key; 
    private int value; 
    boolean hasNewItem; 

    public Mapper() { 
     sm = new TreeMap<String, Integer>; 
     hasNewItem = false; 
    } 

    public void add(String s, int i) { 
     hasNewItem = true; 
     key = s; 
     value = i; 
    } 

    public void run() { 
     while (!Thread.currentThread().isInterrupted()) { 
      try { 
       if (hasNewItem) { 
        // Find if street name exists in map 
        sm.put(key, value); 
        newEntry = false; 
       } 
      } catch (InterruptedException e) { 
       Thread.currentThread().interrupt(); 
      } 
     } 
     // I'm not sure how to give the Map back to main. 
    } 
} 

我不知道我是否采取了正确的做法。我也不知道如何终止Mapper线程并在main中检索地图。我将有多个Mapper线程,但我只在上面的代码中实例化了一个线程。我只是意识到我的Parse类不是线程,但只有另一个类,如果它不覆盖run()方法,所以我认为Parse类应该是某种队列。

和想法?谢谢。编辑: 感谢所有的答复。看起来,由于I/O将成为主要瓶颈,因此并行化将会带来很少的效率收益。但是,出于示范的目的,我是否正确地走上正轨?不知道如何使用多线程,我仍然有点困扰。

+7

从文件中读取是代码的瓶颈。多线程无助于此。 –

+1

使用多线程可以在这里拍摄你的脚。您的线程运行速度可能比@HovercraftFullOfEels指出的Disk IO速度快得多。你打算如何管理哪个线程读取多少行。如果一个或多个线程由于某些不可预知的原因而失败,那么该如何处理? 我建议你在一个线程中处理一个文件,并根据手头的机器选择一种处理方法。如果您的服务器具有128个RAM,请将其读入内存,然后执行处理,如果不是逐行处理。 – JVXR

回答

2

通常,I/O将比内存中任务花费更多的时间。我们将这样的工作称为I/O绑定。并行性最多可能有一个微小的改进,实际上可能会让事情变得更糟。

你当然不需要一个不同的线程来把东西放到地图中。除非您的解析过程非常昂贵,否则您不需要其他线程。

如果你有这些任务的其他线程,他们可能会花大部分时间坐在等待下一行被读取。

即使并行化I/O也不一定有帮助,并且可能会受到影响。即使您的CPU支持并行线程,您的硬盘驱动器可能也不支持并行读取。

编辑:

我们所有的评论谁在这个假设的任务可能是I/O限制 - 因为这是真正的频繁。但是,从下面的评论来看,这种情况是一个例外。更好的答案应该包括下面的第四条评论:

测量读取文件中所有行而不处理它们所需的时间。比较读取和处理它们的时间。这会给你一个松散的上限,你可以节省多少时间。这可能会降低线程同步的新成本。

+0

所以最好的做法就是全部连续完成。 – dman33

+0

如果您将阅读和处理分离为两个线程得到了一些改进,它可能很小,但需要花费更多的开发时间/风险和更复杂的代码来维护。也就是说,我不确定我们对硬盘驱动器的评论如何适用于固态驱动器(SSD)。任何其他人都在关注与SSD并行读取的评论? –

+0

对于演示程序,我可以使用上述方法进行任何改进?我知道这不会有太大的帮助,特别是对于生产代码来说这可能不值得,但我仍然很好奇。 – dman33

6

为什么你需要多个线程?你只有一个磁盘,它只能运行得如此之快。几乎可以肯定的是,多线程并不能帮助解决这种情况。如果确实如此,那么从用户的角度来看它会非常小。多线程不是你的问题。从巨大的文件中读取是你的瓶颈。

+0

这是真的,我最大的瓶颈肯定是从文件中读取。如果有一个线程不断从IO中读取,而另一个线程解析并将这些项目放入地图,会不会有助于提高速度? – dman33

+0

@ dman33:不,它不会帮助。 –

+0

对于演示程序,我可以使用上述方法进行任何改进?我知道这不会有太大的帮助,特别是对于生产代码来说这可能不值得,但我仍然很好奇。 – dman33

0

您不妨阅读Amdahl's Law。由于你的大部分工作都是严格串行的(IO),你可以通过对其余部分进行多线程获得微不足道的改进。当然不值得创建水密多线程代码的代价。

也许你应该寻找一个新的玩具例子来平行。

+0

我在使用这个例子的特定需求。目前整个程序运行时间约为9000毫秒,单独一行读取输入是800毫秒,所以我认为如果我平行一点,至少可以看到一些改进。我在考虑只使用两个线程,一个是阅读,另一个是其他。 – dman33

+0

你有没有尝试分析你的代码?在尝试优化之前计算花费的时间是明智的。 –