1

我正在运行一个多线程 Java 应用程序,它获取对实例进行分类的请求。为了能够同时运行多个线程,我的应用程序在线程之间共享一个Classifier对象和一个Instances对象。Instances 对象仅包含属性的相关数据,并且没有任何与之关联的实例。

当我的应用程序收到分类请求时,我Instance使用请求的属性数据创建一个对象,并使用 将预生成的Instances对象设置为数据集Instance.setDataset(),例如:

myNewInstance.setDataset(sharedInstances);

然后myNewInstance被发送到共享Classifier

在大多数情况下,它似乎运作良好。但是有时当发生 2 个并发请求时,会从Classifier.distributionForInstance(). 不幸的是,错误消息不清楚,但是我看到了 2 个不同的异常:

Caused by: java.lang.RuntimeException: Queue is empty
at weka.core.Queue.pop(Queue.java:194)
at weka.filters.Filter.output(Filter.java:563)
at weka.filters.unsupervised.attribute.PrincipalComponents.convertInstance(PrincipalComponents.java:626)
at weka.filters.unsupervised.attribute.PrincipalComponents.input(PrincipalComponents.java:812)
at weka.classifiers.meta.RotationForest.convertInstance(RotationForest.java:1114)
at weka.classifiers.meta.RotationForest.distributionForInstance(RotationForest.java:1147)

Caused by: java.lang.NullPointerException
at weka.filters.unsupervised.attribute.Standardize.convertInstance(Standardize.java:238)
at weka.filters.unsupervised.attribute.Standardize.input(Standardize.java:142)
at weka.filters.unsupervised.attribute.PrincipalComponents.convertInstance(PrincipalComponents.java:635)
at weka.filters.unsupervised.attribute.PrincipalComponents.input(PrincipalComponents.java:812)
at weka.classifiers.meta.RotationForest.convertInstance(RotationForest.java:1114)
at weka.classifiers.meta.RotationForest.distributionForInstance(RotationForest.java:1147)

如您所见,当最新发生时,它带有一个空消息字符串。

据我了解,我不能使对象不可变,并且我宁愿不将此部分包装在关键部分中,以便充分利用并发性。我尝试使用构造函数为每个分类请求创建一个不同的“实例”对象Instances(Instances dataset),但是,它没有产生不同的结果。使用不同Classifier的选项不是一种选择,因为构建对象需要花费太多时间并且它需要快速响应(最多 10 到 20 毫秒),据我了解,问题并不依赖于此。

我假设问题来自使用相同的 Instances 对象。根据Instances的文档,构造函数只复制对标头信息的引用,这解释了为什么不能通过创建另一个对象来解决问题。是否有一个选项可以根据先前的对象创建完全不同的 Instances 对象,而无需实时查看所有属性?

任何其他以性能为导向的解决方案也将受到高度赞赏。

谢谢!

4

1 回答 1

4

可能你现在已经解决了这个问题。这仅适用于那些面临类似问题的人。我在一个多线程 Java 应用程序中测试实例,我遇到了同样的异常。要分解问题,您的情况有两个问题:

  • 第一个是您使用相同的Instances对象来为每个请求设置数据。这样,您很可能会遇到可能不会破坏代码但会产生错误结果的并发问题。因为来自不同请求的数据可能会混淆。您最好的选择是Instances为每个请求创建一个新对象。但是,这不是产生您面临的异常的原因。这是第二个问题。
  • 第二个问题是您使用的是相同的Classifier,这就是产生异常的原因。就我而言,自从我构建分类器以来,我就构建并序列化了分类器并将其写入文件。一旦我需要对测试集进行分类,我曾经在每个线程中反序列化对象,给我一个新实例。但是,解决此问题的正确方法是使用weka.classifiers.Classifier.makeCopy(model)静态方法为每个请求制作副本,该方法在内部使用序列化。
于 2013-08-21T00:07:05.633 回答