我正在尝试同时处理多个csv。我的代码如下所示:
public class CSVMain{
private static int count = 3;
public static void main(String[] a){
ExecutorService e = Executors.newFixedThreadPool(300);
for(int i=0;i<count;i++) e.execute(new WebRunner("http://some.host.com"));
e.shutdown();
}
static class WebRunner implements Runnable{
private final String url;
public WebRunner(String url) {
this.url = url;
}
@Override
public void run() {
try {
long now = System.currentTimeMillis();
URL MyUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection) MyUrl.openConnection();
conn.connect();
IOUtils.toByteArray(MyUrl.openStream());
System.out.println(new DateTime().toString("HH:mm:ss,SSS") + " finish thread" + Thread.currentThread().getId() + " in " + (System.currentTimeMillis() - now));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
如果将静态
count
变量设置为1,则将在600-700毫秒的连接时间内完成。当它为2时,我会得到大约1100-1400毫秒,当它为3时,我会得到1700-1900毫秒,依此类推。统计数据感觉是连续的,而不是并行的。
我在这里想念什么吗?
最佳答案
有几点有助于这一点。
首先,您要测量单个Runnable的运行时间,而不是顺序运行(即,运行WebRunner
三次,一次又一次)与并发运行(将它们分配给线程)的总运行时间池,就像您在这里一样)。
另一个重要的事实是并发并不意味着事情将并行执行。 Concurrency is not parallelism他们可能会或可能不会。并发也是高度不确定的。也就是说,什么时候允许线程运行以及它们运行多长时间取决于很多因素,包括操作系统。根据情况,它们甚至可能最终顺序运行(无论线程池的大小如何)。它们甚至看起来似乎是并行执行的,但是它们可能以循环方式执行,而并发和切换的开销却没有太大的好处。并发有很多微妙之处。有关深入的指南,最好的资源是this book。
同样,即使任务确实并行运行,性能也会受到其他限制。您可能具有有限的网络带宽,并且当任务并行运行时,它们可能最终会争夺该有限的资源。计算能力和内存也是如此。
另一个非常重要的事情是,您正在做的是微基准测试的幼稚版本。为了获得更可靠的基准统计数据,您可能应该使用类似The JMH framework之类的方法。这是有关pitfalls of naive java benchmarking和an article on JMH的相关文章
TL; DR;版本是:在没有很多严格要求的情况下,请勿尝试为并发应用程序的性能分配含义。