【问题标题】:Java Observable list causing immense slow down after first useJava Observable 列表在第一次使用后导致速度非常慢
【发布时间】:2021-11-07 21:51:42
【问题描述】:

简介

你好,

我正在开发一个使用多个双向哈希映射和可观察列表的 Java 应用程序。我的代码有效,但我遇到了一个我似乎无法摆脱的奇怪怪癖。我在网上找不到任何关于此的信息,所以我想我会分享它,看看有没有其他人以前见过。

当代码第一次打开时,有一个方法可以查询 MySQL 数据库并提取作者列表(该程序是一个库数据库应用程序)的姓名,这些作者的姓名被分成不同的部分;名字、中间名和姓氏。然后这个方法会遍历缓存的行集并将它们组合在一起,然后将它们添加到我之前提到的双向哈希映射和可观察列表中。然后在整个代码中将这些用于各种目的。

在初始创建后刷新列表的任何时候都会出现此问题。 程序运行时,会不时对数据库进行新查询并刷新列表以确保可获得最新信息。第一次运行该方法时,它会执行我提到的所有这些步骤,大约需要 8 毫秒才能完成。但是当进行刷新时,该时间会跳到大约 1,400 毫秒。值得注意的是,刷新次数越多,时间就越长。 显然,这是一个主要的时间高峰,但我看不到代码中的任何内容来表明导致这种情况的原因。我将解释我如何确定它是下面的可观察列表...

我在下面链接了一张图片,以展示我所说的示例。 请注意,正在处理的作者数量是相同的。其他打印输出是我同时测试的附加信息,与这篇文章无关。

这是方法的代码。

public void createAuthorHashMap() 抛出异常 { 字符串 authorFirstName、authorMiddleName、authorLastName、authorFullName; 整数ID;

    // Get the Cached Row Set for all Authors in the database
    CachedRowSet authorList = connectionCommands.readDatabase(sqlCommands.selectAllAuthor);
        
    // Reset the contents of the hashmap and observable list
    bookAttributes.bidiMapAuthors.clear();
    bookAttributes.listAuthors.clear();
    choiceBoxAuthor.setItems(null);
        
    // Combine the sperate parts of the names from the cached rowset
    while (authorList.next()) {
        ID = authorList.getInt(1);
        authorFirstName = authorList.getString(2);
        authorMiddleName = authorList.getString(3);
        authorLastName = authorList.getString(4);

        if (authorMiddleName == null) {
            authorFullName = (authorFirstName + " " + authorLastName);
        } else {
            authorFullName = (authorFirstName + " " + authorMiddleName + " " + authorLastName);
        }

        // Add the authors to the hashmap and list
        bookAttributes.bidiMapAuthors.put(ID, authorFullName);
        bookAttributes.authors.add(authorFullName);
    }

    // Add the list to the choiceBox and auto-complete textfield
    choiceBoxAuthor.setItems(bookAttributes.authors);
    TextFields.bindAutoCompletion(textFieldAuthor, bookAttributes.listAuthors);
}

这是 hashmap 和 Observable 列表的代码。

// Lists
public static ObservableList<String> FictionGenres = FXCollections.observableArrayList();
public static ObservableList<String> NonFictionGenres = FXCollections.observableArrayList();
public static ObservableList<String> blankList=FXCollections.observableArrayList();
public static ObservableList<String> authors = FXCollections.observableArrayList();
public static ObservableList<String> publishers = FXCollections.observableArrayList();
public static ObservableList<String> languages = FXCollections.observableArrayList();
public static ObservableList<String> series = FXCollections.observableArrayList();

// Hashmaps
public static BidiMap<Integer, String> bidiMapAuthors = new TreeBidiMap<>();
public static BidiMap<Integer, String> bidiMapPublishers = new TreeBidiMap<>();
public static BidiMap<Integer, String> bidiMapFictionGenres = new TreeBidiMap<>();
public static BidiMap<Integer, String> bidiMapNonFictionGenres = new TreeBidiMap<>();
public static BidiMap<Integer, String> bidiMapLanguages = new TreeBidiMap<>();
public static BidiMap<Integer, String> bidiMapSeries = new TreeBidiMap<>();

重要的一点是,哈希映射和列表是创建并存储在一个单独的类中,以便在程序运行期间可以跨多个控制器访问它们。

代码本身并不复杂,并且相当容易理解,但是我想提请您注意的是while循环后面的两行代码。这两行将作者姓名添加到哈希映射和列表中。

bookAttributes.bidiMapAuthors.put(ID, authorFullName);
bookAttributes.authors.add(authorFullName);

测试

我的测试就是这样进行的。我在方法的不同部分放置了计时器,并多次运行它并将减速的原因缩小到我之前提到的两行代码。应该注意的是我得到的时间该方法的所有其他部分都完全符合我的预期。

然后我注释掉了将名称添加到哈希映射的行并且问题仍然存在,但是一旦我将其反转并注释掉将名称添加到列表中的行然后问题立即消失并且从未出现无论我运行该方法多少次都返回。

bookAttributes.authors.add(authorFullName);

这里发生的事情是否有任何原因,或者是否存在我忽略的明显错误并且我只是个白痴?我很好奇,我很感激任何信息!

【问题讨论】:

  • 我建议创建一个minimal reproducible example。您可以使用随机生成的数据而不是 SQL。最有可能的是,在创建它时,您可以将问题缩小到足以自己找到解决方案的范围,如果没有,它将帮助其他人快速重现它,对其进行分析/基准测试并为您提供答案。
  • 问题可能是您每次都在创建新的自动完成绑定,而不是用新值更新现有的绑定(通过清除绑定并向绑定添加新建议)。请参阅stackoverflow.com/questions/45778462/update-autocomplete-javafx 的已接受答案
  • 显而易见(也可能是错误的)答案是,当数据发生变化时,无论听众做什么,都会花费时间。尝试将数据放入临时列表,然后使用ObservableList.setAll。
  • @tgdavies 我刚试过这个,它做了一点改进,但​​只有大约 100 毫秒。就像以前一样,这个方法第一次运行时,它几乎是立即运行的。我认为使用 setAll 方法可能会更快,但我遇到的问题仍然存在。文档也没有为我提供任何有用的信息,但我会继续尝试。
  • @tgdavies 我找到了解决方案。明天我会发布一个详细的解决方案。

标签: java performance observablelist


【解决方案1】:

免责声明 我现在承认,我不能 100% 确定我遇到的问题的根本原因是什么,所以我的解决方案可能对你不起作用。我已经对此进行了测试,直到我几乎失明,我只能提供 80-90% 的确定性。

原因

最初的问题似乎是 while 循环正在写入另一个类中的静态可观察列表。由于静态循环位于全局变量池中,这意味着每次写入列表所需的时间都比正常情况要长一些。在您一次写几百次之前,这不是一个严重的性能问题。

旁注 这就是为什么我不能完全确定这是否真的是问题的原因,因为哈希映射也是静态的并且在同一个外部类中,但它们并没有导致速度变慢。他们从来没有引起任何问题。我唯一的猜测是 Observable 列表进行更改的方式与哈希映射的操作方式不同,尽管我几乎不知道列表是如何工作的以明确说明这一点。

解决方案

感谢@tgdavies 的建议,我通过在与方法相同的类中创建这些列表的实例来解决问题,让方法写入这些类,然后在完成所有类似方法后,我复制了使用“addAll”方法将临时列表的内容添加到更永久的列表中。这一变化极大地减少了运行时间。

   ObservableList<String> tempAuthorList=FXCollections.observableArrayList();
   ObservableList<String> tempPublisherList=FXCollections.observableArrayList();
   ObservableList<String> tempFictionGenreList=FXCollections.observableArrayList();
   ObservableList<String> tempNonFictionGenreList=FXCollections.observableArrayList();
   ObservableList<String> tempSeriesList=FXCollections.observableArrayList();
   ObservableList<String> tempLanguageList=FXCollections.observableArrayList();
   ObservableList<String> blankList=FXCollections.observableArrayList();
        bookAttributes.obvListAuthors.addAll(tempAuthorList);
        bookAttributes.obvListPublishers.addAll(tempPublisherList);
        bookAttributes.obvListFictionGenres.addAll(tempFictionGenreList);
        bookAttributes.obvListNonFictionGenres.addAll(tempNonFictionGenreList); 
        bookAttributes.obvListLanguages.addAll(tempLanguageList);     
        bookAttributes.obvListSeries.addAll(tempSeriesList);

我做的另一件事是实施一个更好的流程来清理选择框内容。似乎这也导致了轻微的放缓。我从另一位名叫@sprinter 的评论者那里得到了这个想法,一旦我这样做了,任何挥之不去的性能问题都消失了。

choiceBoxAuthor.setItems(null); -> choiceBoxAuthor.setItems(blankList);

这些修复在其他地方造成了一些需要修复的小故障,我已经用一堆新值以各种方式对此进行了测试,并且代码似乎每次都按应有的方式运行。从这一点开始的任何事情都应该简单的错误修复!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-15
    • 1970-01-01
    • 1970-01-01
    • 2013-07-08
    • 2016-05-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多