为什么在更改System.out后仍然有输出?

huangapple go评论101阅读模式
英文:

Why is there output even after changing System.out?

问题

我正在使用scpsolver进行一个小型个人项目。该库正在生成输出,我不想看到它。实际上,我报告了这个问题,只是想看看他们会说什么。

没有公开的方法来禁用输出。GLPKSolver类尝试使用GLPK公开的内容来禁用它,但正如下面的评论之一所述,这也没有起作用。

我尝试过修改System.outSystem.err为null输出流,但没有帮助,因为该库显然可以以不同的方式打印到控制台。我仍然不理解这是如何工作的。

最后,有一个我尝试使用的setHook()函数,但即使在底部的输出中也失败了。

我的Solver类

  1. public class Solver {
  2. private static final PrintStream out = System.out;
  3. private static final PrintStream err = System.err;
  4. private static final PrintStream null_stream = new PrintStream(OutputStream.nullOutputStream());
  5. static {
  6. System.setOut(null_stream);
  7. System.setErr(null_stream);
  8. }
  9. public static double[] solve(double[][] A, double[] b, double[] c, double[] lb) {
  10. LinearProgram lp = new LinearProgram(c);
  11. for (int i = 0; i < b.length; i++) {
  12. lp.addConstraint(new LinearEqualsConstraint(A[i], b[i], "c" + i));
  13. }
  14. lp.setLowerbound(lb);
  15. lp.setMinProblem(false);
  16. LinearProgramSolver solver = SolverFactory.newDefault();
  17. double[] sol = solver.solve(lp);
  18. System.out.flush();
  19. System.err.flush();
  20. System.setOut(out);
  21. System.setErr(err);
  22. return sol;
  23. }
  24. }

我重新编译并插入回库中的GLPKSolver.java的片段

  1. solver.enablePrints(false); // 将此设置为“false”以防止打印
  2. System.out.println("Hello, world!");
  3. solver.setHook(new GlpkHookIFC() {
  4. @Override
  5. public void fault(String s) {}
  6. @Override
  7. public void print(String s) {}
  8. });
  9. System.out.println("Hi, world!");

输出:

  1. GLPK Simplex Optimizer, v4.65
  2. 8 rows, 9 columns, 20 non-zeros
  3. 0: obj = -0.000000000e+000 inf = 1.590e+002 (2)
  4. 5: obj = -2.400000000e+003 inf = 0.000e+000 (0)
  5. OPTIMAL LP SOLUTION FOUND
  6. Process finished with exit code 0

特别注意,“Hello, world!”和“Hi, world!”都不在输出中。通过这样做,部分GLPK输出被抑制了。如果我删除所有的System.*重定向,我会得到以下结果。

  1. Hello, world!
  2. Hi, world!
  3. GLPK Simplex Optimizer, v4.65
  4. 8 rows, 9 columns, 20 non-zeros
  5. 0: obj = -0.000000000e+000 inf = 1.590e+002 (2)
  6. 5: obj = -2.400000000e+003 inf = 0.000e+000 (0)
  7. OPTIMAL LP SOLUTION FOUND
  8. x1: 2.0
  9. x2: 0.0
  10. x3: 0.5
  11. x4: 0.0
  12. x5: 4.9
  13. x6: 2.2
  14. x7: 0.0
  15. x8: 0.0
  16. x9: 2.4

有趣的是,输出在“Hello, world!”之后...

英文:

I'm using scpsolver for a little personal project. The library is generating output, which I don't want to see. I actually reported this as a bug, just to see what they say about it.

There's no exposed way to disable the output. The GLPKSolver class attempts to disable itusing what GLPK is exposing to them, but as described in one of the comments below, that isn't doing anything either.

I've tried to alter System.out and System.err to be null output streams but that has not helped, as the library apparently is able to print to the console in a different way. I still don't understand how this works.

Finally, there's a setHook() function I've tried to use but even that has failed, as shown in the output at the bottom.
My Solver class

  1. public class Solver {
  2. private static final PrintStream out = System.out;
  3. private static final PrintStream err = System.err;
  4. private static final PrintStream null_stream = new PrintStream( OutputStream.nullOutputStream() );
  5. static {
  6. System.setOut( null_stream );
  7. System.setErr( null_stream );
  8. }
  9. public static double[] solve ( double[][] A, double[] b, double[] c, double[] lb ) {
  10. LinearProgram lp = new LinearProgram( c );
  11. for ( int i = 0; i < b.length; i++ ) {
  12. lp.addConstraint( new LinearEqualsConstraint( A[i], b[i], "c" + i ) );
  13. }
  14. lp.setLowerbound( lb );
  15. lp.setMinProblem( false );
  16. LinearProgramSolver solver = SolverFactory.newDefault();
  17. double[] sol = solver.solve( lp );
  18. System.out.flush();
  19. System.err.flush();
  20. System.setOut( out );
  21. System.setErr( err );
  22. return sol;
  23. }
  24. }

Snippet from the GLPKSolver.java that I'm re-compiling in inserting back into the library

  1. solver.enablePrints(false); // turn this to "false" to prevent printouts
  2. System.out.println("Hello, world!");
  3. solver.setHook( new GlpkHookIFC() {
  4. @Override
  5. public void fault ( String s ) {}
  6. @Override
  7. public void print ( String s ) {}
  8. } );
  9. System.out.println("Hi, world!");

Output:

  1. GLPK Simplex Optimizer, v4.65
  2. 8 rows, 9 columns, 20 non-zeros
  3. 0: obj = -0.000000000e+000 inf = 1.590e+002 (2)
  4. 5: obj = -2.400000000e+003 inf = 0.000e+000 (0)
  5. OPTIMAL LP SOLUTION FOUND
  6. Process finished with exit code 0

In particular, notice that "Hello, world!" and "Hi, world!" are both absent from the output. Some small portion of the GLPK output is suppressed by doing this. If I remove all the System.* redirects, this is what I get.

  1. Hello, world!
  2. Hi, world!
  3. GLPK Simplex Optimizer, v4.65
  4. 8 rows, 9 columns, 20 non-zeros
  5. 0: obj = -0.000000000e+000 inf = 1.590e+002 (2)
  6. 5: obj = -2.400000000e+003 inf = 0.000e+000 (0)
  7. OPTIMAL LP SOLUTION FOUND
  8. x1: 2.0
  9. x2: 0.0
  10. x3: 0.5
  11. x4: 0.0
  12. x5: 4.9
  13. x6: 2.2
  14. x7: 0.0
  15. x8: 0.0
  16. x9: 2.4

Interestingly, the output comes after hello world...

答案1

得分: 1

以下是翻译好的部分:

这个输出是由scpsolver调用的一个本地库生成的。本地库可以直接写入JVM的标准输出流,而无需经过System.out和System.err对象,通常会这样做,因为从本地代码中使用这些对象相当不方便。

除非本地库本身具备关闭输出的功能,否则禁用输出并不容易。我不熟悉scpsolver或它使用的库,但我可以在有时间的时候查看一下。在一般情况下,您可能需要创建一个新的本地库,以便关闭输出。

更新: 经过一些搜索,我发现在底层本地库中有一种关闭终端输出的方法

> 使用GLPK API的程序员可以通过调用glp_term_out来启用和禁用终端输出。hook函数glp_term_hook可用于拦截终端输出。还提供了更精细的输出控制,但本文不涵盖 — 请查阅GLPK API手册。

所以您只需要确保调用这些函数。简单吧?在SCPSolver源代码中,我看到有一个尝试关闭来自本地库的输出:

  1. solver.enablePrints(false); // 将此设置为“false”以防止打印输出

但这个调用到C代码本地库实际上什么都没做,因为禁用打印的代码被注释掉了。事实上,它只是泄漏了一点内存:

  1. JNIEXPORT void JNICALL
  2. Java_org_gnu_glpk_GlpkSolver_enablePrints(JNIEnv *env, jobject obj,
  3. jboolean enable)
  4. {
  5. info_t *info=malloc(sizeof(info_t));
  6. info->env = env;
  7. info->obj = obj;
  8. //lib_set_fault_hook((void*)info, enable ? NULL : &_fault_hook_fn);
  9. //lib_set_print_hook((void*)info, enable ? NULL : &_print_hook_fn);
  10. }

也许有另一种禁用输出的方法,可以在scpsolver.lpsolver.GLPKSolver中设置一个“hook”到GlpkSolver solver对象上,但是代码编写的方式使您无法访问这个对象。

我建议将scpsolver.lpsolver.GLPKSolver的代码复制到您自己项目中的一个类中,并用一个调用solver.setHook来替换对solver.enablePrints的调用。

英文:

The output you see is produced by a native library that scpsolver calls. Native libraries can write directly to the JVM's standard output streams without going through the System.out and System.err objects, and often do because using these objects from native code is pretty inconvenient.

Disabling the output is not easy, unless the native library itself includes a capability to do it. I'm not familiar with scpsolver or the libraries it uses but I can have a look when I get the time. In the general case you may need to create a new native library just to turn the output off.

Update: After spelunking a little I see that there is a way to turn off terminal output in the underlying native library:

> Programmers using the GLPK API can enable and disable terminal output by calling glp_term_out. The hook function glp_term_hook can be used to intercept terminal output. Finer grain output control is also provided but is not covered here — consult the GLPK API manual instead.

So all you need to do is make sure these functions get called. Simple right? In the SCPSolver source code I see that there is an attempt at turning off the output from the native library:

  1. solver.enablePrints(false); // turn this to "false" to prevent printouts

But this call to the C-code native library doesn't actually do anything because the code to disable printing is commented out. In fact, all it does it leak a little bit of memory:

  1. JNIEXPORT void JNICALL
  2. Java_org_gnu_glpk_GlpkSolver_enablePrints(JNIEnv *env, jobject obj,
  3. jboolean enable)
  4. {
  5. info_t *info=malloc(sizeof(info_t));
  6. info->env = env;
  7. info->obj = obj;
  8. //lib_set_fault_hook((void*)info, enable ? NULL : &_fault_hook_fn);
  9. //lib_set_print_hook((void*)info, enable ? NULL : &_print_hook_fn);
  10. }

There may be another way to disable the output, by setting a "hook" on the GlpkSolver solver object in scpsolver.lpsolver.GLPKSolver, but with the way the code is written you have no way to access this object.

I would recommend copying the code of scpsolver.lpsolver.GLPKSolver to a class in your own project, and replacing the call to solver.enablePrints with a call to solver.setHook.

huangapple
  • 本文由 发表于 2020年8月10日 12:19:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/63334080.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定