内存管理

psutil

psutil.virtual_memory()可以查看本机的内存使用,其中total表示总的物理内存,available表示可以立即分配给进程而无需系统进入交换的内存。(但我认为他讲的也没有特别清楚,比如availablefree之间的关系)

具体实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import psutil
import os

if __name__ == '__main__':
mem = psutil.virtual_memory()
# 系统总计内存
zj = float(mem.total) / 1024 / 1024 / 1024
# 系统已经使用内存
ysy = float(mem.used) / 1024 / 1024 / 1024
# 系统空闲内存
kx = float(mem.available) / 1024 / 1024 / 1024

print('系统总计内存:%.4fGB' % zj)
print('系统已经使用内存:%.4fGB' % ysy)
print('系统空闲内存:%.4fGB' % kx)
print(u'当前进程的内存使用:%.4f GB' % (psutil.Process(os.getpid()).memory_info().rss / 1024 / 1024 / 1024))
print(u'cpu个数:', psutil.cpu_count())

运行结果:

1
2
3
4
5
系统总计内存:11.7141GB
系统已经使用内存:4.1249GB
系统空闲内存:7.0015GB
当前进程的内存使用:0.0112 GB
cpu个数: 6

memory_profile

除此之外python查看内存还可以通过memory_profiler,在测试函数前加上@profile,在运行代码时加上-m memory_profiler就可以了解函数每一步代码的内存占用。

guppy

如果我们关注对象的内存占用,可以使用guppy。guppy直接打印出对应各种python类型(list、tuple、dict等)分别创建了多少对象,占用了多少内存。

具体实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
from guppy import hpy
import random
def my_func():
result = []
def _get():
return chr(random.randint(0,100))
for i in range(10):
mk = [_get() for i in range(10)]
result.extend(mk)
return "".join(result)
if __name__ == '__main__':
profile = hpy()
print(profile.iso(my_func()))

参考文章:

https://psutil.readthedocs.io/en/latest/

https://blog.csdn.net/zhou_xiong1130/article/details/108990167

读取文件

在python读取文件一般采用下述代码

1
2
3
with open(fname, 'r', encoding='utf-8') as f:  # 打开文件
lines = f.readlines() # 读取指针位置之后所有行
line = f.readline() # 读取指针位置所在行

f其实是文件指针位置,一个文件只有一个指针,readlines是将文件从指针位置读到结尾,读完后指针在结尾,此时再使用readline就没有东西可以读了。此时,我们可以使用seek来帮助文件指针移动到指定位置。

以读取文件首行和尾行的代码为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
fname = 'test.txt'

with open(fname, 'r', encoding='utf-8') as f: # 打开文件
lines = f.readlines() # 读取所有行
first_line = lines[0] # 取第一行
last_line = lines[-1] # 取最后一行

print('文件' + fname + '第一行为:'+ first_line)
print('文件' + fname + '最后一行为:' + last_line)

# 第二种
with open(fname, 'rb') as f: # 打开文件
# 在文本文件中,没有使用b模式选项打开的文件,只允许从文件头开始,只能seek(offset,0)

first_line = f.readline() # 取第一行
offset = -50 # 设置偏移量

while True:
"""
file.seek(off, whence=0):从文件中移动off个操作标记(文件指针),正往结束方向移动,负往开始方向移动。
如果设定了whence参数,就以whence设定的起始位为准,0代表从头开始,1代表当前位置,2代表文件最末尾位置。
"""
f.seek(offset, 2) # seek(offset, 2)表示文件指针:从文件末尾(2)开始向前50个字符(-50)
lines = f.readlines() # 读取文件指针范围内所有行

if len(lines) >= 2: # 判断是否最后至少有两行,这样保证了最后一行是完整的
last_line = lines[-1] # 取最后一行
break

# 如果off为50时得到的readlines只有一行内容,那么不能保证最后一行是完整的
# 所以off翻倍重新运行,直到readlines不止一行
offset *= 2

print('文件' + fname + '第一行为:' + first_line.decode())
print('文件' + fname + '最后一行为:' + last_line.decode())

参考文章:

https://zhuanlan.zhihu.com/p/98007747