【问题标题】:How to efficiently initializing a large, static data table with Tomcat如何使用 Tomcat 高效地初始化大型静态数据表
【发布时间】:2017-03-22 09:19:28
【问题描述】:

我从 Java/Tomcat 开始,我正在努力解决一个用 C++ 很容易解决的问题。

我的网络服务(单一网络应用程序)通过使用输入值在预先计算的大型表格中查找数字答案来工作。我正在为这个表的初始化而苦苦挣扎。

问题详情:

  • 数据表很大(3000x3000);
  • 数据是预先计算的,这种计算成本很高(它 需要几个小时);
  • 数据是静态的,经过计算后永远不会改变 给定实例;

在 C++ 中,我只需定义一个静态 const 数组并内联初始化它。我在Java中无法做到这一点,显然Java中没有静态数据初始化的概念,它需要生成初始化代码并且该代码不能大于64k。事实上,我什至无法在 Eclipse 中加载带有静态初始化的文件,它会挂掉。

所以我需要从磁盘上的静态文件初始化表。我试图在 WEB-INF/static 上放置一个 .csv 文件,但发现无法从我的 Java 代码中可靠地打开它(例如,绝对路径将位于我的开发和生产环境的不同位置)。

这是我当前的类定义(带有用于初始化的模拟数据):

package com.hmt.restjersey;

public final class G {
    static public final float[][] data = new float[3000][3000];

    //TODO: actual initialization from file
    static {
        Logger.writeEventLog("Initializing G table...");

        for (int alpha = 0; alpha < 3000; alpha++) {
            for (int beta = 0; beta < 3000; beta++) {
                data[alpha][beta] = 1.0f / (1 + alpha + beta);
            }
        }
        Logger.writeEventLog("G table initialized.");
    }
}

所以,我的问题:

  • 如何可靠地访问数据文件(WEB-INF/static/data.csv)来初始化表?
  • .csv 文件是有效加载数字数据的最佳方式吗?

另外,由于表很大,我希望在服务器中有一个它的实例以节省内存并加快初始化速度。如何确保所有 servlet 进程共享一个实例?

【问题讨论】:

  • 您将拥有多少个 Web 应用程序(WAR)来访问如此庞大的数据?如果您所有的 servlet 都在同一个 webapp 中,它们可以通过静态变量(b/c 它是同一个类加载器)或通过应用程序级别的 ServletContext 轻松共享数据(作为旁注,我建议您注意这一点,尤其是当涉及 OOD 和分发问题时,这是另一个问题)
  • 您可能可以将数据文件添加到类路径中,然后通过this.getClass().getClassLoader().getResourceAsStream("data.csv") 加载数据。关于高效加载数值数据的最佳方式,您也可以使用csv 或使用protobuf 或其他序列化工具序列化的准备好的数据。
  • Java中肯定有静态数据。
  • 我的意思是静态数据初始化,而不是“静态”关键字。在 C 中,如果您声明一个变量,如:“const static data[]={1 ,2, 3}”,则数据将直接从二进制文件中访问。在 Java 中,数组将在运行时创建和初始化。
  • 并不是那么大:3,000 * 3,000 * 4 = 36,000,000 = 36 megs 来保存 32 位(4 个八位字节)float 原语。

标签: java tomcat


【解决方案1】:

这是我的两分钱:

  1. 关于内存共享,如果所有 servlet 都在同一个 WAR(webapp)中,那么它们共享静态变量(因为它是同一个类加载器),但使用 ServletContext 会更好,这只是为了这个,请参阅ServletContext
  2. 正如 ServletContext 示例(上面的链接)所示,您不一定需要静态初始化程序 - 您可以使用 ServletContextListener 在应用程序启动时进行初始化(顺便说一下,您也可以在“getter”中按需进行初始化' 的海量数据)。

  3. 如果您想在 2 个不同的 WAR 之间共享内存,我不知道一个简单的解决方案。从理论上讲,如果具有静态变量的类在 TOMCAT_HOME/lib 中,则可以共享它,但 iMHO 它令人困惑和奇怪

  4. 将计算放入文件/存储中是个好主意,因为您可能会发现自己正在重新启动 Tomcat!
  5. 关于如何定位文件,我同意 dmitrievanthony 关于 getResourceAsStream 的评论。基本上它允许您从类路径中获取文件(与用于定位代码的相同),一个简单的示例是将其放在 /WEB-INF/classes/data.csv 中,请参见示例代码Here(我个人喜欢当这种方法被包装在 Spring 框架的“资源”中时,但它可能是一种矫枉过正)。
  6. 请注意:正如我在上面的评论中提到的,我试图回答你对你选择的设计的直接问题,但如果我站在你的立场上,我会停下来考虑这个设计(例如易于在服务器之间分发?它是模块化的和可单元测试的吗?可以用数据库或 MongoDB 甚至单独的“dataService”WAR 替换“data.csv”吗?)。但是如果你已经考虑过请忽略这句话...

已编辑:ServletContext 示例,没有静态字段:

// Class to encapsulate date:
public class G{
   private double[][] data;
   public static G loadData(){
      data=...// complex loading
   }
}
// Usage in ServletContextListener:
public class MyListener implements ServletContextListener{
   public void contextInitialized(ServletContext ctx) {
         G g= G.loadData();
         ctx.put("myData", g);
   }
// Usage is Servlet:
doGet(...){
    G g=(G) getServletContext().getAttribute("myData");
}

单例模式替代方案(但我建议注意可测试性和模块化,您可能还想看看 SpringMVC 等框架,但让我们从简单的开始):

// Singleton:
public class G{
   private volatile double[][] data;
   private G instance;
   public static G getInstance(){
       // I don't synchronize because I rely on ServletContextListener to initialize once       
       if(data==null) 
           data=... // complex loading
       return data;
   }
}
// ServletContextListener:
public void contextInitialized(ServletContext ctx) {
   G.getInstance();
}
// Usage in servlet:
doGet(){
   G g=G.getInstance(); // I don't like it in terms of OOD, but it works
}

【讨论】:

  • 1.是的,这是一个单一的 WAR(我编辑了问题以澄清这一点); 2. ServletContext 看起来太复杂了,特别是我需要初始化的大量数据; 5. 这对我的静态类不起作用,因为我没有“this”; 6. 应用程序比这复杂得多,我还有其他表需要在数据库中,因为它们会发生变化并且需要在服务器之间共享;
  • 感谢您的澄清。我已经修改了答案以包含 ServletContext 或 Singleton 的代码大纲。请注意,如果数据和复杂性封装在“G 类”中,那么您的评论 (2) 还不错。关于(5)你不需要“this”,你可以做例如“Thread.currentThread().getContextClassLoader()” - 请参阅(5)中的链接
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-05
  • 2016-01-11
  • 1970-01-01
  • 2016-11-28
  • 2012-11-07
  • 1970-01-01
相关资源
最近更新 更多