【问题标题】:How can I print multiple lines, having subsequent lines replacing each of them independently (Python)如何打印多行,并让后续行独立替换每一行(Python)
【发布时间】:2016-08-03 18:03:47
【问题描述】:

我正在运行一个并行工作的程序,利用多处理模块中的Pool 对象。

我想要做的是并行运行一个函数 n 次,每个函数都有一个单独的加载百分比,我希望它更新每个函数的百分比而不替换其他百分比......示例:

f(x):
    while x < 0:
        print 'For x = {0}, {1}% completed...\r'.format(x, percentage),

我会并行运行该函数多次。

我想要达到的效果如下,对于 f(10000000), f(15000000), f(7000000):

For x = 10000000, 43% completed
For x = 15000000, 31% completed
For x = 7000000, 77% completed

并且百分比将在各自的行中更新,而不会替换 x 的其他值,在此函数中 f 将同时运行 3 次。

我尝试使用回车“\r”,但它会替换每一行,只会造成混乱。

感谢您抽出宝贵时间阅读这篇文章!希望你能告诉我。

我使用的是 Python 2.7,但如果只能通过 Python 3 实现,我愿意接受建议。

【问题讨论】:

  • 你检查过 curses 库吗?
  • 我不确定它是否支持多个并发状态栏,但你可以看看这里引用的库:stackoverflow.com/questions/3002085/…
  • 将输出存储在数组中,刷新输出完成,再次打印数组。我不确定,只是建议。我猜,这就是你要找的东西!

标签: python printing parallel-processing percentage lines


【解决方案1】:

诅咒

正如@Keozon 在 cmets 中提到的,实现此目的的一种方法是使用 curses 库。

python网站上有good guide for curses。

ANSI 转义码

或者,您可以尝试使用ANSI escape codes 来移动光标。

这是在 Python3 中,但它在任何版本中都可以正常工作,您只需要更改打印语句(或 from __future__ import print_function)。

print('Hello')                                     
print('World')                                     
                                                   
print('\033[F\033[F\033[K', end='') # Up, Up, Clear line
                                                   
# Cursor is at the 'H' of 'Hello'                  
                                                   
print('Hi') # Overwriting 'Hello'                  
                                                   
# Cursor is at the 'W' of 'World'                  
                                                   
print('\033[E', end='') # Down                     
                                                   
# Cursor is on the blank line after 'World'        
                                                   
print('Back to the end')   

                    
              

输出:

Hi         
World          
Back to the end

编辑:

我在这里为你做了太多的工作,但是,嘿,这里基本上是使用我上面提到的 ANSI 方法的完整解决方案:

import time
import random


class ProgressBar:
    def __init__(self, name):
        self._name = name
        self._progress = 0

    @property
    def name(self):
        return self._name

    def get_progress(self):
        """
        Randomly increment the progress bar and ensure it doesn't go
        over 100
        """
        self._progress += int(random.random()*5)
        if self._progress > 100:
            self._progress = 100

        return self._progress


class MultipleProgressBars:
    def __init__(self, progress_bars):
        self._progress_bars = progress_bars
        self._first_update = True
        self._all_finished = False

    @property
    def all_finished(self):
        """
        A boolean indicating if all progress bars are at 100
        """
        return self._all_finished

    def update(self):
        """
        Update each progress bar
        """
        # We don't want to move up and clear a line on the first run
        # so we have a flag to make sure this only happens on later
        # calls
        if not self._first_update:
            # Move up and clear the line the correct number of times
            print('\033[F\033[K'*len(self._progress_bars),end='', sep='')

        num_complete = 0  # Number of progress bars complete
        for progress_bar in self._progress_bars:
            name = progress_bar.name
            progress = progress_bar.get_progress()

            if progress == 100:
                num_complete += 1

            # Print out a progress bar (scaled to 40 chars wide)
            print(
                name.ljust(10),
                '[' + ('='*int(progress*0.4)).ljust(40) + ']',
                str(progress)+'%')

        if num_complete == len(self._progress_bars):
            self._all_finished = True

        self._first_update = False  # Mark the first update done


# Create a list of ProgressBars and give them relevant names
progress_bars = [
    ProgressBar('James'),
    ProgressBar('Bert'),
    ProgressBar('Alfred'),
    ProgressBar('Frank')
]

# Create a new instance of our MultipleProgressBars class
mpb = MultipleProgressBars(progress_bars)

# Keep updating them while at least one of them is still active
while not mpb.all_finished:
    mpb.update()
    time.sleep(0.2)

【讨论】:

  • 非常感谢!稍后我会去尝试并返回结果!
  • 请注意,这只是写在顶部,所以在 pancake 顶部写 hello 将导致 helloke。我相信是\033[K 清除了从光标到行尾的所有内容。
  • @zondo 是的,你是对的。我已经更新了我的答案来纠正这个问题。
  • 再次感谢您的回答。对此,我真的非常感激。我遇到的问题是,由于该函数是并行运行的,因此无法到达每个不同 x 的每个 % 的位置,因此我无法知道要在每次打印中替换哪一行。例如:函数正在打印some % loaded for x = some number,并且是随机打印的,因为它都是同时运行的。我唯一能想到的是为x = some number 选择一条打印线,但如果我知道x 的每个值,那就是效率低下。
  • 不幸的是,您可能必须更改它的工作方式才能使其按您希望的方式工作。以防万一您不知道,python 有一个 GIL 这意味着根据您使用线程的目的,您实际上可能不会获得性能优势。但是,“潜在的阻塞或长时间运行的操作,例如 I/O、图像处理和 NumPy 数字运算,发生在 GIL 之外”,因此这取决于您在线程中执行的操作。
猜你喜欢
  • 2021-08-16
  • 1970-01-01
  • 2014-03-15
  • 2017-04-11
  • 1970-01-01
  • 2023-01-23
  • 2011-02-21
  • 1970-01-01
相关资源
最近更新 更多