场景:
在我的应用程序中,有3个进程正在其各自文件夹中的共享驱动器上复制文档。
一旦将任何文档复制到共享驱动器上(通过任何进程),目录观察器(Java)代码就会拾取该文档并使用“ Process”调用Python脚本,并对文档进行一些处理。代码段如下:
Process pr = Runtime.getRuntime().exec(pythonCommand);
// retrieve output from python script
BufferedReader bfr = new BufferedReader(new InputStreamReader(pr.getInputStream()));
String line = "";
while ((line = bfr.readLine()) != null) {
// display each output line from python script
logger.info(line);
}
pr.waitFor();
目前,我的代码一直等到该文档上的python代码执行完成。只有在此之后,它才会拾取下一个文档。 Python代码需要30秒才能完成。
处理完文档后,文档将从当前文件夹移至存档或错误文件夹。
请在下面的场景屏幕截图中找到:
问题是什么?
我的代码是以顺序方式处理文档的,因此我需要并行处理文档。
由于Python代码大约需要30秒,因此目录观察程序创建的某些事件也将丢失。
如果短时间内要发送约400个文档,则文档处理将停止。
我在找什么?
用于并行处理文档的设计解决方案。
如果出现文档处理失败的情况,则必须自动处理待处理的文档。
我也尝试了Spring Boot调度,但是仍然仅按顺序处理文档。
是否可以作为后台进程并行调用Python代码。
很长的问题很抱歉,但是我在很多天都被这个问题困扰,并且已经看过很多类似的问题。
谢谢!
参考方案
一种选择是使用JDK提供的ExecutorService
,它可以执行Runnable
和Callable
任务。您将需要创建一个实现Runnable
的类,该类将执行您的Python脚本,并且在收到新文档后,您需要创建该类的新实例并将其传递给ExecutorService
。
为了说明它是如何工作的,我们将使用一个简单的Python脚本,该脚本以线程名作为参数,打印其执行的开始时间,休眠10秒并显示结束时间:
import time
import sys
print "%s start : %s" % (sys.argv[1], time.ctime())
time.sleep(10)
print "%s end : %s" % (sys.argv[1], time.ctime())
首先,我们实现运行脚本的类,并将在构造函数中获得的名称传递给它:
class ScriptRunner implements Runnable {
private String thread;
ScriptRunner(String thread) {
this.thread = thread;
}
@Override
public void run() {
try {
ProcessBuilder ps = new ProcessBuilder("py", "test.py", thread);
ps.redirectErrorStream(true);
Process pr = ps.start();
try (BufferedReader in = new BufferedReader(new InputStreamReader(pr.getInputStream()))) {
String line;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
}
pr.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
}
}
然后,我们创建main
方法,该方法使用固定数量的5个并行线程创建ExecutorService
,并以1秒的中断将10个ScriptRunner
实例传递给它:
public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 1; i <= 10; i++) {
executor.submit(new ScriptRunner("Thread_" + i));
Thread.sleep(1000);
}
executor.shutdown();
}
如果运行此方法,我们将看到由于指定的限制,该服务最多具有5个并行运行的任务,其余任务进入队列并在释放的线程中启动:
Thread_1 start : Sat Nov 23 11:40:14 2019
Thread_1 end : Sat Nov 23 11:40:24 2019 // the first task is completed..
Thread_2 start : Sat Nov 23 11:40:15 2019
...
Thread_5 end : Sat Nov 23 11:40:28 2019
Thread_6 start : Sat Nov 23 11:40:24 2019 // ..and the sixth is started
...
Thread_10 end : Sat Nov 23 11:40:38 2019
Spring Boot-使用上下文路径时在根级别的静态内容 - java假设我有一个application.yml内容server: port: 8000 context-path: /rest 因此,将像这样访问所有控制器和htmlhttp://server:8000/rest/controller因此,具有此配置...有可能在不更改其上下文路径的情况下将一些静态html元素添加到其根级别? (我已经将index.html添加…
Spring Boot:java.time.Duration的默认序列化从字符串更改为数字 - java我们最近从Spring Boot 2.1.9升级到2.2.1,这导致我们的测试失败。调查导致结果,默认情况下java.time.Duration类型现在序列化为不同的序列。现在,我们将得到"PT15M",而不是在JSON消息中包含字符串"900.0"。 POJO定义如下所示@JsonProperty(required …
Spring Boot-如何将application.yml属性定义为application.properties - java我目前正在尝试使用我的Spring Boot Web应用程序设置s3存储桶以添加/删除图像。我遵循的指南使用以下application.yml属性:amazonProperties: endpointUrl: https://s3.us-east-2.amazonaws.com accessKey: XXXXXXXXXXXXXXXXX secretKey: …
Java:“自动装配”继承与依赖注入 - javaImprove this question 我通常以常见的简单形式使用Spring框架: 控制器服务存储库通常,我会在CommonService类中放一个通用服务,并使所有其他服务扩展到类中。一个开发人员告诉我,最好在每个服务中插入CommonClass而不是使用继承。我的问题是,有一个方法比另一个更好吗? JVM或性能是否会受到另一个影响?更新资料Comm…
有什么方法可以使用Spring Boot,Liquibase和sql脚本进行集成测试吗? - java我使用liquibase设置数据库模式。我禁用休眠以创建任何东西。因此,我的import.sql被忽略。在liquibase创建表之后,有什么方法可以配置spring boot或liquibase或其他任何部分来加载测试数据? 参考方案 如果您需要一些粗糙的东西(即,不是用于实际的数据迁移),则可以使用Spring's JDBC initializ…