所以我有一个程序,我需要向URL发送很多(如10,000)GET请求,我需要它尽可能快.当我第一次创建程序时,我只是将连接放入for循环中,但它确实很慢,因为它必须等待每个连接完成才能继续.我想让它更快,所以我尝试使用线程,它使它更快,但我仍然不满意.

我猜测正确的方法是使用异步连接并连接到所有URL.这是正确的方法吗?

此外,我一直在努力了解线程以及它们是如何工作的,但我似乎无法理解它.我所使用的计算机配有Intel Core i7-3610QM四核处理器.根据英特尔网站上有关该处理器的规格,它有8个线程.这是否意味着我可以在Java应用程序中创建8个线程,它们将同时运行?超过8,没有速度增加?

“性能”选项卡下任务管理器中“线程”旁边的数字究竟代表什么?目前,我的任务管理器显示“线程”超过1,000.为什么这是这个数字,如果那是我的所有处理器支持,它怎么能超过8呢?
我还注意到,当我尝试使用500个线程作为测试程序时,任务管理器中的数字增加了500但它的速度与我将其设置为使用8个线程相同.因此,如果数量根据我在Java应用程序中使用的线程数增加,那为什么速度相同呢?

另外,我尝试用Java中的线程做一个小测试,但输出对我来说没有意义.
这是我的Test类:

import java.text.SimpleDateFormat;
import java.util.Date;

public class Test {

    private static int numThreads = 3;
    private static int numLoops = 100000;
    private static SimpleDateFormat dateFormat = new SimpleDateFormat("[hh:mm:ss] ");

    public static void main(String[] args) throws Exception {

        for (int i=1; i<=numThreads; i++) {
            final int threadNum = i;
            new Thread(new Runnable() {
                public void run() {
                    System.out.println(dateFormat.format(new Date()) + "Start of thread: " + threadNum);
                    for (int i=0; i<numLoops; i++)
                        for (int j=0; j<numLoops; j++);
                    System.out.println(dateFormat.format(new Date()) + "End of thread: " + threadNum);
            }
            }).start();
            Thread.sleep(2000);
        }

    }
}

这会产生如下输出:

[09:48:51] Start of thread: 1
[09:48:53] Start of thread: 2
[09:48:55] Start of thread: 3
[09:48:55] End of thread: 3
[09:48:56] End of thread: 1
[09:48:58] End of thread: 2

为什么第三个线程立即开始和结束,而第一个和第二个线程各占5秒?如果我添加更多3个线程,对于2以上的所有线程都会发生同样的事情.

对不起,如果这是一个长篇阅读,我有很多问题.
提前致谢.

解决方法

您的处理器有8个内核,而不是线程.事实上,这意味着在任何给定时刻只能运行8件事.但这并不意味着您仅限于8个线程.

当一个线程同步打开一个到URL的连接时,它会在等待远程服务器返回它时经常休眠.当该线程正在休眠时,其他线程可以正常工作.如果你有500个线程并且所有500个线程都处于休眠状态,那么你就不会使用cpu的任何内核.

另一方面,如果你有500个线程并且所有500个线程想要做某事,那么它们不能同时运行.为了处理这种情况,有一个特殊的工具.处理器(或者更可能是操作系统或两者的某种组合)具有调度器,该调度器确定在任何给定时间哪些线程在处理器上主动运行.有许多不同的规则,有时是随机活动,可以控制这些调度程序的工作方式.这可以解释为什么在上面的示例中,线程3似乎总是先完成.也许调度程序更喜欢线程3,因为它是主线程调度的最新线程,有时候无法预测行为.

现在回答你关于表现的问题.如果打开连接从不涉及睡眠,那么无论是同步处理还是异步处理都无关紧要,您将无法获得超过8个线程的任何性能提升.实际上,打开连接所花费的大部分时间都花在睡觉上.异步和同步之间的区别在于如何处理睡眠时间.从理论上讲,你应该能够在两者之间获得几乎相同的表现.

使用多线程模型,您只需创建比核心更多的线程.当线程进入休眠状态时,他们让其他线程工作.这有时可以更容易处理,因为您不必在线程之间编写任何调度或交互.

使用异步模型,您只能为每个核心创建一个线程.如果该线程需要休眠,那么它不会休眠,但实际上必须有代码来处理切换到下一个连接.例如,假设打开连接(A,B,C)有三个步骤:

while (!connectionsList.isEmpty()) {
  for(Connection connection : connectionsList) {

    if connection.getState() == READY_FOR_A {
      connection.stepA();
      //this method should return immediately and the connection
      //should go into the waiting state for some time before going
      //into the READY_FOR_B state
    }
    if connection.getState() == READY_FOR_B {
      connection.stepB();
      //same immediate return behavior as above
    }
    if connection.getState() == READY_FOR_C {
      connection.stepC();
      //same immediate return behavior as above
    }
    if connection.getState() == WAITING {
      //Do nothing,skip over
    }
    if connection.getState() == FINISHED {
      connectionsList.remove(connection);  
    }
  }
}

请注意,线程在任何时候都不会休眠,因此没有任何关键点拥有比核心更多的线程.最终,无论是采用同步方法还是异步方法都是个人偏好的问题.只有在绝对极端情况下,两者之间才会存在性能差异,您需要花费很长时间进行分析才能达到应用程序瓶颈的程度.

听起来你创造了很多线程而没有获得任何性能提升.这可能有很多原因.

>你建立一个连接可能实际上没有睡觉,在这种情况下我不希望看到超过8个线程的性能提升.我不认为这是可能的.
>所有线程都可能正在使用一些常见的共享资源.在这种情况下,其他线程无法工作,因为休眠线程具有共享资源.是否有所有线程共享的对象?该对象是否有任何同步方法?
>您可能有自己的同步.这可能会产生上述问题.
>每个线程都可能需要进行某种设置/分配工作,这会破坏您通过使用多个线程获得的好处.

如果我是你,我会使用像JVisualVM这样的工具在运行一些少量线程时分析你的应用程序(20). JVisualVM有一个很好的彩色线程图,它将显示线程何时运行,阻塞或休眠.这将帮助您了解线程/核心关系,因为您应该看到正在运行的线程数小于您拥有的核心数.此外,如果您看到许多被阻塞的线程,那么这可以帮助您引导您的瓶颈(如果您看到许多被阻塞的线程使用JVisualVM在该时间点创建线程转储并查看线程被阻止的内容).

java – 了解线程异步的更多相关文章

  1. iOS:核心图像和多线程应用程序

    我试图以最有效的方式运行一些核心图像过滤器.试图避免内存警告和崩溃,这是我在渲染大图像时得到的.我正在看Apple的核心图像编程指南.关于多线程,它说:“每个线程必须创建自己的CIFilter对象.否则,你的应用程序可能会出现意外行为.”这是什么意思?我实际上是试图在后台线程上运行我的过滤器,所以我可以在主线程上运行HUD(见下文).这在coreImage的上下文中是否有意义?

  2. ios – 多个NSPersistentStoreCoordinator实例可以连接到同一个底层SQLite持久性存储吗?

    我读过的关于在多个线程上使用CoreData的所有内容都讨论了使用共享单个NSPersistentStoreCoordinator的多个NSManagedobjectContext实例.这是理解的,我已经使它在一个应用程序中工作,该应用程序在主线程上使用CoreData来支持UI,并且具有可能需要一段时间才能运行的后台获取操作.问题是NSPersistentStoreCoordinator会对基础

  3. ios – XCode断点应该只挂起当前线程

    我需要调试多线程错误.因此,为了获得生成崩溃的条件,我需要在代码中的特定点停止一个线程,并等待另一个线程到达第二个断点.我现在遇到的问题是,如果一个线程遇到断点,则所有其他线程都被挂起.有没有办法只停止一个线程,让其他线程运行,直到它们到达第二个断点?)其他更有趣的选择:当你点击第一个断点时,你可以进入控制台并写入这应该在该断点处暂停当前上下文中的线程一小时.然后在Xcode中恢复执行.

  4. ios – 在后台线程中写入Realm后,主线程看不到更新的数据

    >清除数据库.>进行API调用以获取新数据.>将从API检索到的数据写入后台线程中的数据库中.>从主线程上的数据库中读取数据并渲染UI.在步骤4中,数据应该是最新数据,但我们没有看到任何数据.解决方法具有runloops的线程上的Realm实例,例如主线程,updatetothelatestversionofthedataintheRealmfile,因为通知被发布到其线程的runloop.在后台

  5. ios – NSURLConnectionLoader线程中的奇怪崩溃

    我们开始看到我们的应用启动时发生的崩溃.我无法重现它,它只发生在少数用户身上.例外情况是:异常类型:EXC_BAD_ACCESS代码:KERN_INVALID_ADDRESS位于0x3250974659崩溃发生在名为com.apple.NSURLConnectionLoader的线程中在调用时–[NSBlockOperationmain]这是该线程的堆栈跟踪:非常感谢任何帮助,以了解可能导致这种崩

  6. ios – 合并子上下文时的NSObjectInaccessbileExceptions

    我尝试手动重现,但失败了.是否有其他可能发生这种情况的情况,是否有处理此类问题的提示?解决方法在创建子上下文时,您可以尝试使用以下行:

  7. ios – 从后台线程调用UIKit时发出警告

    你如何处理项目中的这个问题?

  8. ios – 在SpriteKit中,touchesBegan在与SKScene更新方法相同的线程中运行吗?

    在这里的Apple文档AdvancedSceneProcessing中,它描述了更新方法以及场景的呈现方式,但没有提到何时处理输入.目前尚不清楚它是否与渲染循环位于同一个线程中,或者它是否与它并发.如果我有一个对象,我从SKScene更新方法和touchesBegan方法(在这种情况下是SKSpriteNode)更新,我是否要担心同步对我的对象的两次访问?解决方法所以几天后没有回答我设置了一些实验

  9. ios – 在后台获取中加载UIWebView

    )那么,有一种方法可以在后台加载UIWebView吗?解决方法如果要从用户界面更新元素,则必须在应用程序的主队列(或线程)中访问它们.我建议您在后台继续获取所需的数据,但是当需要更新UIWebView时,请在主线程中进行.你可以这样做:或者您可以创建一个方法来更新UIWebView上的数据,并使用以下方法从后台线程调用它:这将确保您从正确的线程访问UIWebView.希望这可以帮助.

  10. ios – 何时使用Semaphore而不是Dispatch Group?

    我会假设我知道如何使用DispatchGroup,为了解问题,我尝试过:结果–预期–是:为了使用信号量,我实现了:并在viewDidLoad方法中调用它.结果是:从概念上讲,dispachGroup和Semaphore都有同样的目的.老实说,我不熟悉:什么时候使用信号量,尤其是在与dispachGroup合作时–可能–处理问题.我错过了什么部分?

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部