在Java线程中执行代码需要更长的时间

在Java线程中执行代码需要更长的时间,java,multithreading,Java,Multithreading,我需要尽快执行多达10个HTTP Post操作。所有帖子都指向同一个目的地,为了简化操作,现在可以假设它们都在执行相同的操作。每毫秒都很重要。 当作为主代码的一部分执行时,执行单个HTTP post操作通常需要50毫秒,没有任何线程: long start = System.currentTimeMillis( ); response = httpClient.execute(httppost, context); long end = System.currentTimeMillis( );

我需要尽快执行多达10个HTTP Post操作。所有帖子都指向同一个目的地,为了简化操作,现在可以假设它们都在执行相同的操作。每毫秒都很重要。 当作为主代码的一部分执行时,执行单个HTTP post操作通常需要50毫秒,没有任何线程:

long start = System.currentTimeMillis( );
response = httpClient.execute(httppost, context);
long end = System.currentTimeMillis( );
long diff = end - start;
System.out.println(Thread.currentThread().getName() + ": Difference is: " + diff);
但为了一次完成一些操作,我为每个HTTP post操作创建了一个线程,并向每个线程传递相同的HttpClient对象,包括PoolighttpClientConnectionManager:

protected HttpClient createHttpClient() {
    PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
    cm.setMaxTotal(20);
    cm.setDefaultMaxPerRoute(24);
    RequestConfig.Builder requestBuilder = RequestConfig.custom();
    requestBuilder = requestBuilder.setConnectTimeout(5000);
    requestBuilder = requestBuilder.setSocketTimeout(5000);

    HttpClientBuilder builder = HttpClientBuilder.create();
    builder.setDefaultRequestConfig(requestBuilder.build());
    builder.setConnectionManager(cm);

    return builder.build();
}

CloseableHttpClient httpClient = (CloseableHttpClient) createHttpClient();
HttpParams httpParams = new DefaultHttpClient().getParams();

Runnable threadJob = new MyRunnable(httpClient, post);

Thread one = new Thread(threadJob);
Thread two = new Thread(threadJob);
Thread three = new Thread(threadJob);
Thread four = new Thread(threadJob);
Thread five = new Thread(threadJob);
Thread six = new Thread(threadJob);
Thread seven = new Thread(threadJob);
Thread eight = new Thread(threadJob);
Thread nine = new Thread(threadJob);
Thread ten = new Thread(threadJob);
one.start();
two.start();
three.start();
four.start();
five.start();
six.start();
seven.start();
eight.start();
nine.start();
ten.start();
在MyRunnable类中,相同的50ms操作似乎需要更长的时间。注意,我的指标中没有包括创建线程等的开销,我希望这会增加总体时间,但让我困惑的是,为什么同一个httpclient.execute()操作在线程内部比在线程外部花费的时间更长。在MyRunnable的run()方法中:

我的机器有2个内核,但有4个逻辑处理器。
如果执行4个线程,记录的时间通常如下:

58毫秒 155ms 160毫秒 179ms

<> P>这是“N”线程的始末,第一个线程完成登记时间比“50ms”的时间长一些,剩下的时间大约是3倍。10个线程的另一个典型结果集:

52毫秒 156ms 156ms 160毫秒 156ms 161ms 175ms 158ms 176毫秒 178ms

问题:

  • 我的“之前和之后”日志记录方法是否是一种可靠的方法,它需要多长时间

  • 这就是在线程内执行http post操作时的方式,还是我可以做些什么来降低平均时间?(除了购买更强大的机器)


  • 您还应该尝试测量用户和系统时间。看看有没有办法做到这一点。现在,您正在测量挂钟时间,这可能无法显示正确的时间

    在我看来,可能发生的情况是,您一次启动所有线程,它们都会很快在
    httpClient.execute上阻塞。然后它们都在大致相同的时间完成,每个都测量整个系统等待操作发生的时间,即170毫秒

    连接管理器中可能还有其他功能来限制活动请求、全局或每个路由的连接数

    在MyRunnable类中,同样的50ms操作似乎需要一段时间 好的,再长一点。注意:我没有包括创建 我的指标中的线程等–我希望这会增加总时间, 但让我困惑的是为什么同一个httpclient.execute() 操作在线程内部花费的时间比在线程外部花费的时间长

    您首先需要了解多线程是如何工作的。这并不是说当你创建和启动一个
    线程时,它只是并行运行,而是等待轮到它执行
    run()
    方法(当线程数>处理器时)

    换句话说,当有一个线程在运行(或者线程数<处理器)时,您看不到任何开销,因为处理器是空闲的,只执行您的请求。现在,我们来看另一个场景,在这个场景中,线程的运行量比可用的处理器要多,显然,线程需要一些时间才能轮到它们,这被称为上下文切换开销,因此您会明显注意到响应时间上的一些差异

    您可能有兴趣了解线程如何优先执行
    run()
    方法,您可以看看这个。简单地说,这实际上是由JVM内的线程调度器处理的

    此外,我建议您阅读并理解多线程工作原理的基础知识

    我的“之前和之后”记录方法是可靠的多长时间的方法 需要多少时间

    您的
    System.currentTimeMillis()
    很好,或者您也可以使用Java8中的API

    这就是执行http post操作时的方式吗 在一个线程内,或者我能做些什么来获得平均值 时间到了?(除了购买更强大的机器)


    我建议不要自己手动创建和维护线程,而是使用类似于
    ExecutorService.newFixedThreadPool(10)
    的API。这可能不会减少平均时间,而是有助于将线程作为一个池进行正确管理。

    您是否为基准测试预热了VM?如果不是的话,你应该使用基准测试框架。是的,我知道它是如何工作的,这就是为什么我包括了一个4线程的例子,这与逻辑处理器的数量相同。即使我只做两个线程,完成第一个线程所需的时间也比完成第二个线程所需的时间少得多。你怎么知道处理器实际上是空闲的?你在监视吗?不,我不知道或者怎么检查?实际上,我的一个疑问是,核心的数量还是逻辑处理器的数量才是最重要的。我假设的是后者。你可以在这里查看:谢谢,我会看看关于这个链接的建议。我已经做好了充分的准备,在执行线程时,它所花费的时间是可以预期的,但是我想确保我正在采取每一步来尽可能减少平均时间。让我困惑的是,即使是两个线程也会表现出这种行为,例如,典型的结果是第一个线程63毫秒,第二个线程169毫秒。也许测量用户/系统时间可以解释更多正在发生的事情……进一步分析,你是对的,所有线程(第一个除外)都在同一时间完成。conn管理器允许我设置最大连接数,或每个路由的连接数。。。但是降低这些数字只会增加总时间。我看不出还有什么可以在conn管理器上进行调整,以帮助解决所有线程都希望同时执行httpClient.execute的情况——我天真地假设,正如
    long start = System.currentTimeMillis( );
    response = httpClient.execute(httppost, context);
    long end = System.currentTimeMillis( );
    long diff = end - start;
    System.out.println(Thread.currentThread().getName() + ": Difference is: " + diff);