python多线程队列下载文件,为什么内存会一直增长不释放

352 views
Skip to first unread message

chao jay

unread,
Jan 15, 2020, 1:38:03 AM1/15/20
to python-cn(华蟒用户组,CPyUG 邮件列表)

sen Long

unread,
Jan 15, 2020, 4:37:17 AM1/15/20
to pyth...@googlegroups.com

是不是因为你这些线程都设置成守护线程,另外问一下这些线程对象激活的时候都是空任务,是不是queue.join()会给所有所动对象发信号激活。

发送自 Windows 10 邮件应用

 

发件人: chao jay
发送时间: Wednesday, January 15, 2020 2:38 PM
收件人: python-cn(华蟒用户组,CPyUG 邮件列表)
主题: [CPyUG] python多线程队列下载文件,为什么内存会一直增长不释放

 

--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
详情: http://code.google.com/p/cpyug/wiki/CpyUg
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了Google网上论坛上的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+...@googlegroups.com
要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/python-cn/85c9d935-4297-452c-bb46-0b56784a8c01%40googlegroups.com

 

sen Long

unread,
Jan 15, 2020, 4:57:26 AM1/15/20
to pyth...@googlegroups.com
我看了一下Queue库的文档 调用空队列会默认阻塞的当你加入新任务然后激活,其实一开始在那个node处就阻塞了。如果有问题我估计是因为你设置那些线程为守护进程,所以任务完成以后线程对象不释放,可以把这行代码屏蔽试试t.daemon = True,默认是False

chao jay

unread,
Jan 15, 2020, 5:33:36 AM1/15/20
to python-cn(华蟒用户组,CPyUG 邮件列表)
嗨,谢谢回复

有测试过把多线程不设置为守护进程,内存还是不会释放,内存会一直叠加到机器down掉。

好像requests请求的数据全被叠加到内存里面了

很奇怪,你有更多的建议吗


在 2020年1月15日星期三 UTC+8下午5:57:26,Noob写道:
我看了一下Queue库的文档 调用空队列会默认阻塞的当你加入新任务然后激活,其实一开始在那个node处就阻塞了。如果有问题我估计是因为你设置那些线程为守护进程,所以任务完成以后线程对象不释放,可以把这行代码屏蔽试试t.daemon = True,默认是False

 

 

发送自 Windows 10 邮件应用

 

发件人: chao jay
发送时间: Wednesday, January 15, 2020 2:38 PM
收件人: python-cn(华蟒用户组,CPyUG 邮件列表)
主题: [CPyUG] python多线程队列下载文件,为什么内存会一直增长不释放

 

--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
详情: http://code.google.com/p/cpyug/wiki/CpyUg
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了Google网上论坛上的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。

要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+unsubscribe@googlegroups.com
要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/python-cn/85c9d935-4297-452c-bb46-0b56784a8c01%40googlegroups.com

 

chao jay

unread,
Jan 15, 2020, 6:29:15 AM1/15/20
to python-cn(华蟒用户组,CPyUG 邮件列表)
如果把链接变成 http://www.sse.com.cn/disclosure/listedinfo/announcement/c/2019-12-27/603818_2018_nA.pdf ,一切都是正常的,内存不会一直叠加,会正常释放


在 2020年1月15日星期三 UTC+8下午5:57:26,Noob写道:
我看了一下Queue库的文档 调用空队列会默认阻塞的当你加入新任务然后激活,其实一开始在那个node处就阻塞了。如果有问题我估计是因为你设置那些线程为守护进程,所以任务完成以后线程对象不释放,可以把这行代码屏蔽试试t.daemon = True,默认是False

 

 

发送自 Windows 10 邮件应用

 

发件人: chao jay
发送时间: Wednesday, January 15, 2020 2:38 PM
收件人: python-cn(华蟒用户组,CPyUG 邮件列表)
主题: [CPyUG] python多线程队列下载文件,为什么内存会一直增长不释放

 

--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
详情: http://code.google.com/p/cpyug/wiki/CpyUg
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了Google网上论坛上的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。

要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+unsubscribe@googlegroups.com
要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/python-cn/85c9d935-4297-452c-bb46-0b56784a8c01%40googlegroups.com

 

Jing Liu

unread,
Jan 15, 2020, 3:06:06 PM1/15/20
to python-cn:CPyUG
你不应该使用 r.text,应该使用 r.content

On Tue, Jan 14, 2020 at 10:38 PM chao jay <secretn...@gmail.com> wrote:

--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
详情: http://code.google.com/p/cpyug/wiki/CpyUg
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了Google网上论坛上的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+...@googlegroups.com
要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/python-cn/85c9d935-4297-452c-bb46-0b56784a8c01%40googlegroups.com

sen Long

unread,
Jan 15, 2020, 8:05:35 PM1/15/20
to pyth...@googlegroups.com

那肯定啊,你那个下载过程,下载的文件又没有放到磁盘上面去了,就一个return,其实相当于你从网路上一直打开文件到内存。那些线程也不会自动施放,阻塞在queue.get(),所以那些文件的打开线程一直都隐形存在也不会自动施放。不知道我猜的对不对,你可以在queue队列空了的时候,回收所有线程试试。

 

发送自 Windows 10 邮件应用

 

发件人: Jing Liu
发送时间: Thursday, January 16, 2020 4:06 AM
收件人: python-cn:CPyUG
主题: Re: [CPyUG] python多线程队列下载文件,为什么内存会一直增长不释放

allenh

unread,
Jan 15, 2020, 10:12:32 PM1/15/20
to pyth...@googlegroups.com
能调试么,看看哪些对象比较大而多



--
 -HuAlonG from gmail

allenh

unread,
Jan 15, 2020, 10:18:34 PM1/15/20
to pyth...@googlegroups.com
刚看到前面的回复说request对象比较多
是不是因为process_queue函数一直不退,所以self.func_main(node)的返回值一直没有释放呢?
不知道py的垃圾回收机制在函数执行过程中会不会清理函数内没有用的下层函数返回值
--
 -HuAlonG from gmail

依云

unread,
Jan 16, 2020, 1:56:05 AM1/16/20
to pyth...@googlegroups.com
On Thu, Jan 16, 2020 at 11:18:07AM +0800, allenh wrote:
> 刚看到前面的回复说request对象比较多
> 是不是因为process_queue函数一直不退,所以self.func_main(node)的返回值一直没有释放呢?
> 不知道py的垃圾回收机制在函数执行过程中会不会清理函数内没有用的下层函数返回值

tracemalloc 看一下?

--
Best regards,
lilydjwg

Linux Vim Python 我的博客:
https://blog.lilydjwg.me/
--
A: Because it obfuscates the reading.
Q: Why is top posting so bad?

Mengyang Li

unread,
Jan 17, 2020, 4:14:05 PM1/17/20
to pyth...@googlegroups.com
库用的不正确,在stack overflow回答了

--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
详情: http://code.google.com/p/cpyug/wiki/CpyUg
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了 Google 网上论坛的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+...@googlegroups.com
要在网络上查看此讨论,请访问 https://groups.google.com/d/msgid/python-cn/20200116065508.GA304176%40lilyforest.localdomain


--
Best regards,
ᶘ ᵒᴥᵒᶅ

chao jay

unread,
Jan 19, 2020, 8:26:09 PM1/19/20
to pyth...@googlegroups.com
谢谢Mengyang Li,可是为什么用另外的url去下载pdf时候,memory不会增长呢

Mengyang Li <mayl...@gmail.com> 于2020年1月18日周六 上午5:14写道:
您收到此邮件是因为您订阅了Google网上论坛上的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+...@googlegroups.com
要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/python-cn/CADq5vF4%2B-LAcfzM5afcSUXg0WR232uFoPux6WnMa9%3D5OnEB4Yg%40mail.gmail.com

Jing Liu

unread,
Jan 19, 2020, 10:32:13 PM1/19/20
to python-cn:CPyUG
你调用 r.text 的时候,就相当于要求 requests 把下载的数据解码,变成一个字符串。
但你下载的数据实际上是一个二进制的文件,并不能解码。requests 不知道那串二进制数据应该使用什么编码去解码。
这个时候, requests 会调用一个叫 chardet 的库去猜测那个数据应该是什么编码。
一般来说,只有你确定你的数据是某一种编码的时候,才应该使用 chardet 去猜。不然 chardet 会占用很多的 CPU 和内存,然后返回探测失败或是错误的结果。
你的情况就是应该使用 r.content 的时候,误用了 r.text 。导致 chardet 徒劳的去猜那个文件是什么编码。
chardet 探测时内存和CPU占用的大小,取决于输入数据的内容。有的内容很快就返回了,也不占内存,有的内容探测更难,会占用很多的CPU和内存。

sen Long

unread,
Jan 19, 2020, 11:49:41 PM1/19/20
to pyth...@googlegroups.com

这个光猜不行,最好自己测试一下。

 

那个探测编码我觉得不是,r.txt 已经给明了字符编码,然后会根据系统默认编码,编码正确和错误是人的主观问题,对计算机没有什么意义,而且出错的话,python的异常处理程序,或者操作系统会终止程序。

还有我对那个内存一直增长的问题不是很清楚,这个代码我没运行过,每个进程有内存使用限制,超过了系统会自动终止程序吧。这个程序是不是因为异常直接被关掉了,还是运行中会占用了很多的内存,然后施放了。

 

首先看看线程有没有施放(测试方法reput some elements into The queue, 看看线程队列还在不在,如果在,那就很可能下载的对象被当做一个临时文件对象存贮,线程关闭之前就算没有引用文件也不会关闭,但是这个对象如果是存放在stack中的话返回时会自动施放,但是这里有可能是存放在堆中的,因为下载对象可能在返回以后还需要用,所有一般文件打开需要调用一个close()。文件对象被回收有两个条件 1 对象引用数0 打开线程关闭,临时文件一搬就是先创建一个文件,然后unlink实现的,这样进程关闭临时文件会自动被关闭。

 

 

主要我还没有弄清楚你的问题,这些就当练练打字吧。

发送自 Windows 10 邮件应用

 

发件人: Jing Liu
发送时间: Monday, January 20, 2020 11:32 AM


收件人: python-cn:CPyUG
主题: Re: [CPyUG] python多线程队列下载文件,为什么内存会一直增长不释放

 

你调用 r.text 的时候,就相当于要求 requests 把下载的数据解码,变成一个字符串。

Jing Liu

unread,
Jan 20, 2020, 1:55:52 AM1/20/20
to python-cn:CPyUG
我的天!你的回复里,错误好多。

On Sun, Jan 19, 2020 at 8:49 PM sen Long <family...@gmail.com> wrote:
>
> 这个光猜不行,最好自己测试一下。

这个你是猜的吧。我真的自己测试过。 :D

>
>
> 那个探测编码我觉得不是,r.txt 已经给明了字符编码,

r.text 的源代码会调用 apparent_encoding [1],然后调用 chardet.detect [2] 去探测编码
[1] https://github.com/psf/requests/blob/d2f65af033942a50890b29ab0159b385c426ea5b/requests/models.py#L874-L875
[2] https://github.com/psf/requests/blob/d2f65af033942a50890b29ab0159b385c426ea5b/requests/models.py#L732

你如果把那个PDF文件保存下来,单独把文件内存读出来,然后传给 chardet.detect 函数,你就能重现高CPU,高内存占用的现象。

> 然后会根据系统默认编码,

你从一个网站上下载的数据,怎么可能会自动以你的系统进行编码?你在windows上下载,网站会给你gb18030编码后的数据,你在linux系统下载,网站给你utf-8编码后的数据?

> 编码正确和错误是人的主观问题,对计算机没有什么意义,

当然有意义。一个二进制流,怎么转成字符串跟编码方式紧密相关。
记得当年windows记事本写“联通”,保存后再打开就乱码的BUG吗?就是记事本猜错编码了。

> 而且出错的话,python的异常处理程序,或者操作系统会终止程序。

如果代码抛异常,整个线程就退了,这个时候CPU占用和内存占用都不会增加。但OP的情况明显不是。

>
> 还有我对那个内存一直增长的问题不是很清楚,这个代码我没运行过,每个进程有内存使用限制,超过了系统会自动终止程序吧。这个程序是不是因为异常直接被关掉了,还是运行中会占用了很多的内存,然后施放了。
>

如果程序被OS退掉,那整个进程就没了,不可能出现CPU和内存高占用的现象。

>
>
> 首先看看线程有没有施放(测试方法reput some elements into The queue, 看看线程队列还在不在,

OP开了个线程池,在所有任务处理完之前,线程本来就不应该退出的。退出了就不可能内存占用高了。

> 如果在,那就很可能下载的对象被当做一个临时文件对象存贮,线程关闭之前就算没有引用文件也不会关闭,

requests 下载的时候,数据是在内存里的,不是放在临时文件的。
https://github.com/psf/requests/blob/d2f65af033942a50890b29ab0159b385c426ea5b/requests/models.py#L775

> 但是这个对象如果是存放在stack中的话返回时会自动施放,但是这里有可能是存放在堆中的,因为下载对象可能在返回以后还需要用,所有一般文件打开需要调用一个close()。

CPython里,所有的 Python 对象都是在堆上的。哪怕你的变量只在某个函数里使用,那也是堆上的。
https://docs.python.org/3.8/c-api/memory.html
Memory management in Python involves a private heap containing *all
Python objects* and data structures

> 文件对象被回收有两个条件 1 对象引用数0, 打开线程关闭,临时文件一搬就是先创建一个文件,然后unlink实现的,这样进程关闭临时文件会自动被关闭。
>
CPython 使用引用计数来管理对象,跟线程没关系。完全可能线程没结束,但对象被销毁了。也可能线程结束了,但线程里创建的对象由于被其它对象引用,还活着。
> 要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/python-cn/5e25314e.1c69fb81.758bc.d2e1%40mx.google.com

sen Long

unread,
Jan 20, 2020, 2:56:29 AM1/20/20
to pyth...@googlegroups.com

你在搞笑吗?下载的文件全放在内存里,你下载一个10G的文件就占用10G的内存?明显是在内存里打开一个流,和一个临时文件关联起来。Cpython,只是翻译一下代码罢了,还不是一样调用操作系统的系统调用,以及对文件对象的管理不管是为了兼容还是简便我觉得都是委托操作系统管理的。还有我说那个探测编码,你都没懂我的逻辑。我说如果探测错误,线程就会被关闭。如果没有被关闭,就说明和探测编码没有什么关系。我说的默认的编码,那个探测编码是不是一个一个编码去试?英语也好,日语也好,中文也好或者一堆乱码对计算机有区别吧?他怎么知道你要那个?一般你不指定,就是默认UTF-8.

 

发送自 Windows 10 邮件应用

 

发件人: Jing Liu
发送时间: Monday, January 20, 2020 2:55 PM

依云

unread,
Jan 20, 2020, 10:04:51 AM1/20/20
to pyth...@googlegroups.com
On Mon, Jan 20, 2020 at 03:56:05PM +0800, sen Long wrote:
> 你在搞笑吗?下载的文件全放在内存里,你下载一个10G的文件就占用10G的内存?明显是在内存里打开一个流,和一个临时文件关联起来。Cpython,只是翻译一下代码罢了,还不是一样调用操作系统的系统调用,以及对文件对象的管理不管是为了兼容还是简便我觉得都是委托操作系统管理的。还有我说那个探测编码,你都没懂我的逻辑。我说如果探测错误,线程就会被关闭。如果没有被关闭,就说明和探测编码没有什么关系。我说的默认的编码,那个探测编码是不是一个一个编码去试?英语也好,日语也好,中文也好或者一堆乱码对计算机有区别吧?他怎么知道你要那个?一般你不指定,就是默认UTF-8.

……

代码里就是下载到内存里。你在内存里搞一个文件的话(memfd_create),它是不
对应所谓的「临时文件」的。

没有被关闭才说明有问题,因为 PDF 是二进制数据,不是文本。倒是有可能被识
别为 GBK 之类的编码了,然后转成 Python str 对象时每个字符四字节,就会用
掉很多内存了。

不过这么多内存不释放是挺奇怪的。所以我才提议 tracemalloc 看看,但是你们
还是在玩猜谜游戏。
Reply all
Reply to author
Forward
0 new messages