【问题标题】:Multithreaded (or async) calculation on Spring FrameworkSpring Framework 上的多线程(或异步)计算
【发布时间】:2014-09-04 19:55:05
【问题描述】:

我正在学习 Spring Framework,它非常棒。

我想使用 JAVA 多线程,但不知道如何使用 Spring Framework。

服务代码如下:

//StudentService.java
public List<Grade> loadGradesForAllStudents(Date date) {
    try{
        List<Grade> grades = new ArrayList<Grade>();
        List<Student> students = loadCurrentStudents(); // LOAD FROM THE DB

        for(Student student : students) { // I WANT TO USE MULTITHREAD FOR THIS PART

            // LOAD FROM DB (MANY JOINS)
            History studentHistory = loadStudentHistory(student.getStudentId(), date); 

            // CALCULATION PART
            Grade calculatedGrade = calcStudentGrade(studentHistory, date);

            grades.add(calculatedGrade);
        }
        return grades;
    } catch(Exception e) {
        ...
        return null;
    }
}

如果没有多线程,它会很慢。

我猜 for 循环会导致速度变慢,但我不知道如何解决这个问题。如果给我一个有用的链接或示例代码,我将不胜感激。

我发现 loadStudentHistory 方法与 calcStudentGrade(大约 30 毫秒)相比相当慢(大约 300 毫秒)。

【问题讨论】:

  • 你有什么理由想通过春天来做这件事吗?这可以在没有 Spring 的情况下完成
  • 您的瓶颈在查询中。同时执行更多查询不会解决您的问题,但可能会使问题变得更糟。此外,这与 Spring 无关。

标签: java multithreading spring spring-mvc asynchronous


【解决方案1】:

在具有并发用户的应用程序中为此使用多线程是一个坏主意,因为现在每个查询都使用多个线程和多个连接,而不是让每个请求使用一个线程和一个连接。它不会随着用户数量的增长而扩展。

当我查看您的示例时,我发现了两个可能的问题:

1) 应用程序和数据库之间的往返次数过多,每次往返都需要时间。

2) 不清楚每个查询是否使用单独的事务(您没有在示例代码中说明事务在哪里划分),如果您的查询每个都创建自己的事务,这可能是浪费的,因为每个事务有与之相关的开销。

使用多线程对#1 没有多大帮助(如果确实有帮助,它将给数据库增加更多负载),并且要么对#2 没有影响,要么使情况变得更糟(取决于当前的事务范围;如果您之前在同一个事务中进行过查询,则使用多个线程,它们必须在不同的事务中)。正如已经解释的那样,它不会扩大规模。

我的建议:

1) 使服务具有事务性,如果它还没有,那么它所做的一切都在一个事务中。删除异常捕获/返回空的东西(这会干扰 Spring 希望使用异常来回滚事务的方式)并引入异常处理程序,以便从控制器抛出的任何内容都将被捕获和记录。这将最大限度地减少您创建事务的开销,并使您的异常处理更清晰。

2) 创建一个带回学生列表的查询。这样查询被发送到数据库一次,然后结果集结果以块的形式读回(根据结果集上的获取大小)。您可以自定义查询以仅返回您需要的内容,这样您就不会拥有过多的联接。对查询运行解释计划并确保它使用索引。您将获得更快的查询和更少的往返次数,这将大大提高速度。

【讨论】:

    【解决方案2】:

    简单的解决方案称为stream,这些使您可以在parallel中进行迭代,例如:

    students.stream().parallel().forEach( student -> doSomething(student));
    

    显着提升性能它不会消除数据库查询开销...如果您的数据库管理系统需要大约 300 毫秒来返回结果.... 好吧 ...您要么在 big 数据库上使用 ORM,要么您的查询效率极低,我建议重新分析您当前的解决方案

    【讨论】:

    • 哦,不,我使用的是 JDK 7 :(
    • 然后安装好JDK8 ....它不像java(实际上)绑定到JDK-releases。
    • 您还可以对数据字段进行分段,创建合理数量的线程并让每个线程处理至少一个段...我建议将线程数量保持在可用 CPU 核心的数量-- 大多数情况下为 4 或 8 个。也许尝试通过从一个段的开始到结束运行的数字索引访问相同的线程安全集合 - 这样您将避免在启动线程之前必须迭代整个集合。
    • 显然:journaldev.com/1061/… 正如你所看到的,现在不使用 JDK8 有很大的缺点 - 它增加了相当多的复杂性并且会让你遇到错误。
    • 他……还在我们身边。让所有人都希望他再呆几十年,他创造了一种真正了不起的语言。
    猜你喜欢
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-27
    • 1970-01-01
    • 2013-12-08
    相关资源
    最近更新 更多