如何更改进度条的位置 - 多处理
Posted
技术标签:
【中文标题】如何更改进度条的位置 - 多处理【英文标题】:How to change position of progress bar – multiprocessing 【发布时间】:2017-07-17 00:20:56 【问题描述】:首先,我是 Python 新手。与问题无关,但我不得不提一下。
我正在创建一个爬虫作为我的第一个项目,以了解 Python 中的工作原理,但到目前为止,这是我的主要问题......在使用 requests
和 @ 时了解终端中的“如何获取多个进度条” 987654323@。
我设法完成了所有事情,我只是想要更漂亮的输出,所以我决定添加进度条。我正在使用tqdm
,因为我喜欢它的外观,而且它似乎最容易实现。
这是我下载文件的方法。
def download_lesson(self, lesson_data):
if not 'file' in lesson_data:
return print('=> Skipping... File file_name already exists.'.format(file_name=lesson_data['title']))
response = requests.get(lesson_data['video_source'], stream=True)
chunk_size = 1024
with open(lesson_data['file'], 'wb') as file:
progress = tqdm(
total=int(response.headers['Content-Length']),
unit='B',
unit_scale=True
)
for chunk in response.iter_content(chunk_size=chunk_size):
if chunk:
progress.update(len(chunk))
file.write(chunk)
progress.close()
print('=> Success... File "file_name" has been downloaded.'.format(file_name=lesson_data['title']))
我通过Processing
运行该方法:
# c = instance of my crawling class
# cs = returns the `lesson_data` for `download_lesson` method
p = Pool(1)
p.map(c.download_lesson, cs)
所以一切都很好,因为我在Pool
中使用processes=1
。但是当我运行多个进程时,比如说processes=3
,然后事情开始变得奇怪,我得到了多个进程,一个又一个。
我在tqdm documentation 中发现有position
的参数。这清楚地说明了我在这种情况下所需要的目的。
位置:int,可选 指定打印此条的行偏移量(从 0 开始) 如果未指定则自动。有助于一次管理多个条形图(例如,从线程中)。
但是,我不知道如何设置该位置。我尝试了一些奇怪的东西,例如添加一个应该自增一的变量,但是每当运行 download_lesson
方法时,它似乎并没有做任何递增。总是0
所以位置总是0
。
所以在这种情况下我似乎不太了解......欢迎任何提示、提示或完整的解决方案。谢谢!
更新 #1:
我发现我也可以将另一个参数传递给地图,所以我传递了正在设置的进程数量。 (例如进程=2)
p = Pool(config['threads'])
p.map(c.download_lesson, cs, range(config['threads']))
因此,在我的方法中,我尝试打印出该参数,并且确实得到了0
和1
,因为我在示例中运行2
进程。
但这似乎根本没有做任何事情......
progress = tqdm(
total=int(response.headers['Content-Length']),
unit='B',
unit_scale=True,
position=progress_position
)
我仍然遇到相同的进度条重叠问题。当我手动将位置设置为(例如 10)时,它会在终端中跳转,因此位置确实会移动,但仍然有重叠的 ofc,因为现在两者都设置为 10。但是当动态设置时,它似乎也不起作用。我不明白我的问题是什么......就像地图两次运行此方法时,它仍然为两个进度条提供最新的设置位置。我到底做错了什么?
【问题讨论】:
没有人吗?请...我更新了我的问题,我正在尝试解决这个问题,没有运气! 我认为到目前为止您没有收到回复的一个原因是您的代码无法按原样运行...尽管如此...您是否尝试过使用pathos.pools.ThreadPool
代替?这将提供一个并行线程池而不是使用多个进程——它通常是非常轻量级的快速并行调用的更好选择。要知道的另一件事是multiprocessing
复制您在进程之间传递的对象......所以如果您需要使用共享状态(例如在所有进程中使用计数器),那么您应该考虑使用multiprocess.Value
或multiprocess.Manager
.
谢谢@MikeMcKerns。这帮助我解决了这个问题......
【参考方案1】:
好的,首先我要感谢@MikeMcKerns 的评论... 所以我的脚本有很多变化,因为我想要不同的方法,但最终归结为这些重要的变化。
我的init.py
现在看起来干净多了...
from scraper.Crawl import Crawl
if __name__ == '__main__':
Crawl()
我在scraper.Crawl
类中的方法,对于download_lesson
,现在看起来像这样...
def download_lesson(self, lesson):
response = requests.get(lesson['link'], stream=True)
chunk_size = 1024
progress = tqdm(
total=int(response.headers['Content-Length']),
unit='B',
unit_scale=True
)
with open(lesson['file'], 'wb') as file:
for chunk in response.iter_content(chunk_size=chunk_size):
progress.update(len(chunk))
file.write(chunk)
progress.close()
最后,我有一个专门用于多处理的方法,如下所示:
def begin_processing(self):
pool = ThreadPool(nodes=Helper.config('threads'))
for course in self.course_data:
pool.map(self.download_lesson, course['lessons'])
print(
'Course "course_title" has been downloaded, with total of lessons_amount lessons.'.format(
course_title=course['title'],
lessons_amount=len(course['lessons'])
)
)
如您所知,我对我的课程做了一些重大更改,但最重要的是我必须将这一点添加到我的init.py
if __name__ == '__main__':
其次,我必须使用@MikeMcKerns 建议我看的东西:
from pathos.threading import ThreadPool
因此,通过这些更改,我终于让一切都按我的需要工作了。这是一个快速截图。
即使如此,我仍然不知道为什么 pathos.multiprocessing
使 tqdm
的进度非常糟糕,感谢 Mike 的建议,我设法解决了我的问题。谢谢!
【讨论】:
哦,好吧,如果打印任何消息,例如“已下载的内容”,仍然存在一些错误,所以最后我需要删除进度并只留下打印消息。我想总有一天会有人能够通过 tqdm 做出贡献并解决这个问题。 奇怪的是,经过进一步的测试,当使用 tqdm 时,它不会从字典中下载每一节课。如果有 4 个线程,它使用 4 个线程,并且只从一个 dict 下载 4 个课程,即使可能有 20 个课程。另一个错误...删除tqdm
并使用pathos.threading
而不是pathos.multiprocessing
可以...以上是关于如何更改进度条的位置 - 多处理的主要内容,如果未能解决你的问题,请参考以下文章