ctongfei / progressbar

Terminal-based progress bar for Java / JVM
http://tongfei.me/progressbar/
MIT License
1.07k stars 102 forks source link

Multiple progress bars end up on a single line under osx with 0.9.4 #145

Open spinscale opened 1 year ago

spinscale commented 1 year ago

I am creating multiple progress bars, each one as a task in a thread pool (up to 300). When. the thread pool is running more than one task at once, the progress bars all end up on the same line.

I checked an Terminal.cursorMovementSupported is set to true.

The code looks like this:

executorService.submit(() -> {
    try (CliProgressMonitor progressMonitor = new CliProgressMonitor(message, terminalWidth.get())) {
        // do long running task
    }
});

private static final class CliProgressMonitor extends BatchingProgressMonitor implements AutoCloseable {

    private final ProgressBar progressBar;

    public CliProgressMonitor(String message, int terminalWidth) {
        this.progressBar = new ProgressBarBuilder()
            .setStyle(ProgressBarStyle.UNICODE_BLOCK)
            .setTaskName(message)
            .setMaxRenderedLength(terminalWidth)
            .hideETA()
            .build();
    }

    ...
}

Is there anything wrong with the approach, should the closing of the progressbar be changed or sth?

Thanks for your help!

ctongfei commented 1 year ago

Which environment are you running in? e.g. Linux terminal, or Windows WSL, or in a Docker container?

spinscale commented 1 year ago

Under osx, I tried with iterm2 as well as wezTerm. This is what it looks like..

2022-10-10 14 44 12

So, every "Fetching repo..." is an own progressbar (that is the message), and if you look closely, the last line flips between the 10 concurrent running progresses and only creates a newline once the progress is finished.

Lc3586 commented 1 year ago

I am creating multiple progress bars, each one as a task in a thread pool (up to 300). When. the thread pool is running more than one task at once, the progress bars all end up on the same line.

I checked an Terminal.cursorMovementSupported is set to true.

The code looks like this:

executorService.submit(() -> {
    try (CliProgressMonitor progressMonitor = new CliProgressMonitor(message, terminalWidth.get())) {
        // do long running task
    }
});

private static final class CliProgressMonitor extends BatchingProgressMonitor implements AutoCloseable {

    private final ProgressBar progressBar;

    public CliProgressMonitor(String message, int terminalWidth) {
        this.progressBar = new ProgressBarBuilder()
            .setStyle(ProgressBarStyle.UNICODE_BLOCK)
            .setTaskName(message)
            .setMaxRenderedLength(terminalWidth)
            .hideETA()
            .build();
    }

    ...
}

Is there anything wrong with the approach, should the closing of the progressbar be changed or sth?

Thanks for your help!

maybe you can try this

/**
     * 支持在控制台打印多行进度条
     *
     * @author LCTR
     * @date 2023-05-07
     */
    public class ConsoleMultiProgressBarConsumer
            extends ConsoleProgressBarConsumer {
        final int index;
        final PrintStream out;

        public ConsoleMultiProgressBarConsumer(PrintStream out,
                                               int index) {
            super(out);
            this.out = out;
            this.index = index;
        }

        public ConsoleMultiProgressBarConsumer(PrintStream out,
                                               int maxRenderedLength,
                                               int index) {
            super(out,
                  maxRenderedLength);
            this.out = out;
            this.index = index;
        }

        @Override
        public void accept(String str) {
            out.print(StringExtension.newString("\r\n",
                                                index));

            out.print(matcher.appendTail(sb));
            //super.accept(str);

            out.print(StringExtension.newString("\033[F",
                                                index));
        }
    }
new ProgressBarBuilder()
                                .setTaskName("#01"))
                                .setInitialMax(100)
                                .setConsumer(new ConsoleMultiProgressBarConsumer(new PrintStream(new FileOutputStream(FileDescriptor.out)),
                                                                                 1))
                                .hideEta()
                                .setUpdateIntervalMillis(100)
                                .build();
new ProgressBarBuilder()
                                .setTaskName("#02"))
                                .setInitialMax(100)
                                .setConsumer(new ConsoleMultiProgressBarConsumer(new PrintStream(new FileOutputStream(FileDescriptor.out)),
                                                                                 2))
                                .hideEta()
                                .setUpdateIntervalMillis(100)
                                .build();
new ProgressBarBuilder()
                                .setTaskName("#03"))
                                .setInitialMax(100)
                                .setConsumer(new ConsoleMultiProgressBarConsumer(new PrintStream(new FileOutputStream(FileDescriptor.out)),
                                                                                 3))
                                .hideEta()
                                .setUpdateIntervalMillis(100)
                                .build();
IvanEOD commented 1 year ago

I am creating multiple progress bars, each one as a task in a thread pool (up to 300). When. the thread pool is running more than one task at once, the progress bars all end up on the same line. I checked an Terminal.cursorMovementSupported is set to true. The code looks like this:

executorService.submit(() -> {
    try (CliProgressMonitor progressMonitor = new CliProgressMonitor(message, terminalWidth.get())) {
        // do long running task
    }
});

private static final class CliProgressMonitor extends BatchingProgressMonitor implements AutoCloseable {

    private final ProgressBar progressBar;

    public CliProgressMonitor(String message, int terminalWidth) {
        this.progressBar = new ProgressBarBuilder()
            .setStyle(ProgressBarStyle.UNICODE_BLOCK)
            .setTaskName(message)
            .setMaxRenderedLength(terminalWidth)
            .hideETA()
            .build();
    }

    ...
}

Is there anything wrong with the approach, should the closing of the progressbar be changed or sth? Thanks for your help!

maybe you can try this

/**
     * 支持在控制台打印多行进度条
     *
     * @author LCTR
     * @date 2023-05-07
     */
    public class ConsoleMultiProgressBarConsumer
            extends ConsoleProgressBarConsumer {
        final int index;
        final PrintStream out;

        public ConsoleMultiProgressBarConsumer(PrintStream out,
                                               int index) {
            super(out);
            this.out = out;
            this.index = index;
        }

        public ConsoleMultiProgressBarConsumer(PrintStream out,
                                               int maxRenderedLength,
                                               int index) {
            super(out,
                  maxRenderedLength);
            this.out = out;
            this.index = index;
        }

        @Override
        public void accept(String str) {
            out.print(StringExtension.newString("\r\n",
                                                index));

            out.print(matcher.appendTail(sb));
            //super.accept(str);

            out.print(StringExtension.newString("\033[F",
                                                index));
        }
    }
new ProgressBarBuilder()
                                .setTaskName("#01"))
                                .setInitialMax(100)
                                .setConsumer(new ConsoleMultiProgressBarConsumer(new PrintStream(new FileOutputStream(FileDescriptor.out)),
                                                                                 1))
                                .hideEta()
                                .setUpdateIntervalMillis(100)
                                .build();
new ProgressBarBuilder()
                                .setTaskName("#02"))
                                .setInitialMax(100)
                                .setConsumer(new ConsoleMultiProgressBarConsumer(new PrintStream(new FileOutputStream(FileDescriptor.out)),
                                                                                 2))
                                .hideEta()
                                .setUpdateIntervalMillis(100)
                                .build();
new ProgressBarBuilder()
                                .setTaskName("#03"))
                                .setInitialMax(100)
                                .setConsumer(new ConsoleMultiProgressBarConsumer(new PrintStream(new FileOutputStream(FileDescriptor.out)),
                                                                                 3))
                                .hideEta()
                                .setUpdateIntervalMillis(100)
                                .build();

i dont really understand this, where are the matcher and sb in the accept method coming from?

CoolLoong commented 1 year ago
/**
 * @author Cool_Loong
 */
public class ConsoleMultiProgressBarConsumer extends ConsoleProgressBarConsumer {
    final PrintStream out;
    final boolean first;

    public ConsoleMultiProgressBarConsumer(PrintStream out, boolean isFirst) {
        super(out);
        this.out = out;
        this.first = isFirst;
    }

    public ConsoleMultiProgressBarConsumer(PrintStream out, int maxRenderedLength, boolean isFirst) {
        super(out, maxRenderedLength);
        this.out = out;
        this.first = isFirst;
    }

    @Override
    public void accept(String str) {
        if (first) {
            out.print('\n');
            out.print("-".repeat(this.getMaxRenderedLength()));
        }
        out.print("\r\n");
        super.accept(str);
    }
}
FIRST = new AtomicBoolean(true);

ProgressBar pb = progressBarBuilder.setTaskName("region " + srcRegion.getRegionX() + "," + srcRegion.getRegionZ())
                .setInitialMax(1024)
                .setStyle(ProgressBarStyle.ASCII)
                .setConsumer(new ConsoleMultiProgressBarConsumer(System.out, FIRST.getAndSet(false)))
                .build()

Displaying multiple lines by a “line feed” character.

Lc3586 commented 1 year ago

I am creating multiple progress bars, each one as a task in a thread pool (up to 300). When. the thread pool is running more than one task at once, the progress bars all end up on the same line. I checked an Terminal.cursorMovementSupported is set to true. The code looks like this:

executorService.submit(() -> {
    try (CliProgressMonitor progressMonitor = new CliProgressMonitor(message, terminalWidth.get())) {
        // do long running task
    }
});

private static final class CliProgressMonitor extends BatchingProgressMonitor implements AutoCloseable {

    private final ProgressBar progressBar;

    public CliProgressMonitor(String message, int terminalWidth) {
        this.progressBar = new ProgressBarBuilder()
            .setStyle(ProgressBarStyle.UNICODE_BLOCK)
            .setTaskName(message)
            .setMaxRenderedLength(terminalWidth)
            .hideETA()
            .build();
    }

    ...
}

Is there anything wrong with the approach, should the closing of the progressbar be changed or sth? Thanks for your help!

maybe you can try this

/**
     * 支持在控制台打印多行进度条
     *
     * @author LCTR
     * @date 2023-05-07
     */
    public class ConsoleMultiProgressBarConsumer
            extends ConsoleProgressBarConsumer {
        final int index;
        final PrintStream out;

        public ConsoleMultiProgressBarConsumer(PrintStream out,
                                               int index) {
            super(out);
            this.out = out;
            this.index = index;
        }

        public ConsoleMultiProgressBarConsumer(PrintStream out,
                                               int maxRenderedLength,
                                               int index) {
            super(out,
                  maxRenderedLength);
            this.out = out;
            this.index = index;
        }

        @Override
        public void accept(String str) {
            out.print(StringExtension.newString("\r\n",
                                                index));

            out.print(matcher.appendTail(sb));
            //super.accept(str);

            out.print(StringExtension.newString("\033[F",
                                                index));
        }
    }
new ProgressBarBuilder()
                                .setTaskName("#01"))
                                .setInitialMax(100)
                                .setConsumer(new ConsoleMultiProgressBarConsumer(new PrintStream(new FileOutputStream(FileDescriptor.out)),
                                                                                 1))
                                .hideEta()
                                .setUpdateIntervalMillis(100)
                                .build();
new ProgressBarBuilder()
                                .setTaskName("#02"))
                                .setInitialMax(100)
                                .setConsumer(new ConsoleMultiProgressBarConsumer(new PrintStream(new FileOutputStream(FileDescriptor.out)),
                                                                                 2))
                                .hideEta()
                                .setUpdateIntervalMillis(100)
                                .build();
new ProgressBarBuilder()
                                .setTaskName("#03"))
                                .setInitialMax(100)
                                .setConsumer(new ConsoleMultiProgressBarConsumer(new PrintStream(new FileOutputStream(FileDescriptor.out)),
                                                                                 3))
                                .hideEta()
                                .setUpdateIntervalMillis(100)
                                .build();

i dont really understand this, where are the matcher and sb in the accept method coming from?

oh!that's my fault,I have omitted some irrelevant code,The correct content is this out.print(str);