我有一个6G的tsv文件。文件的内容是数字,最大的数字是57134205。该文件实际上是一个查找表,每行的第一个数字是键,该行的后续数字是映射到该键的值。在python dict的形式中,它类似于:
lookup1=1,2,3,4
lookup2=7,8
..。
因此,我认为这是一些琐碎的东西,并尝试逐行读取文件(我使用的是python 3.7):
R={}
with open(filename) as f:
for line in f:
l=list(map(int,line.split('\t')))
R[l[0]] = set(l[1:])但这毁了我的机器,它有64G的内存(在读完文件之前出现了内存错误)。我怀疑这是由于数字的int类型造成的,所以我尝试将它们保留为str,这相当于更改了行
l=list(map(int,l.split('\t')))至
l=line.split('\t')这仍然失败,我尝试显式地使用np.uint32
l=[np.uint32(i) for i in line.split('\t')]还是失败了。
现在我已经没有主意了。我知道数据结构会比数字本身占用更多的空间,但我仍然很惊讶这个6G文件不能放在64G内存中,除非代码中有一些我完全忽略的bug。如果有什么建议,请告诉我。谢谢你的帮助!
发布于 2019-08-26 18:42:25
每当您发现自己在存储同构数据数组的同时试图节省内存时,您都可以从the array module中受益。
在您的例子中,您应该能够将数据放在一个连续的内存区域中,并像单链表一样对其进行组织,以便以后能够对其进行搜索。您将节省大量内存,但您必须牺牲字典提供的O(1)搜索复杂性,而使用线性搜索算法提供的O(number of loop iterations, apparently?) one (请参阅下面的get_value_at_index函数),如果使用双向链表并考虑前一次搜索中值的偏移,则线性搜索算法可能会进一步优化。
import random
import array
import sys
def write_file(fname: str, nlines: int) -> int:
'''
Write `nlines` lines to file `fname`.
Return the number of entries written.
'''
data_range = range(57134205)
nentries_total = 0
with open(fname, 'w') as f:
for x in range(nlines):
nentries = random.randint(0, 30)
data = random.sample(data_range, nentries)
data.insert(0, x)
nentries_total += nentries + 1
data_str = ','.join(map(str, data))
f.write(data_str + '\n')
return nentries_total
def store_that(fname: str) -> array.array:
result = array.array('L')
next_index = 0
with open(fname) as f:
for line in f:
index, *values = map(int, line.split(','))
next_index += len(values) + 2
result.append(index)
result.append(next_index)
result.extend(values)
return result
def get_value_at_index(array: array.array, index: int) -> array.array:
current_index_offset = 0
next_index_offset = array[current_index_offset + 1]
current_index = array[current_index_offset]
while current_index != index:
current_index = array[next_index_offset]
current_index_offset = next_index_offset
next_index_offset = array[next_index_offset + 1]
return array[current_index_offset + 2:next_index_offset]
FNAME = 'test.txt'
number_of_keys = 2_000
total_size = write_file(FNAME, number_of_keys)
data = store_that(FNAME)
for x in range(10):
index = random.randint(0, number_of_keys)
value = get_value_at_index(data, index)
print(f'data[{index}] == {value}')
print()
actual_size = data.buffer_info()[1]
size_of_object, size_of_data = sys.getsizeof(data), actual_size * data.itemsize
print(f'Key count : {number_of_keys: >7} keys')
print(f'Element count : {total_size: >7} elements')
print(f'With indices : {actual_size: >7} elements ({actual_size / total_size - 1:.3%} overhead)')
print(f'Size of data : {size_of_data:_} bytes')
print(f'Size of object: {size_of_object:_} bytes ({size_of_object / size_of_data - 1:.3%} overhead)')
print(f'\nTotal overhead: {size_of_object / (total_size * data.itemsize) - 1:.3%}')通过这个设置,我得到了如下输出:
Key count : 2000 keys
Element count : 31477 elements
With indices : 33477 elements (6.354% overhead)
Size of data : 133_908 bytes
Size of object: 136_808 bytes (2.166% overhead)
Total overhead: 8.657%请注意,您的结果会有所不同,因为此代码随机化了要存储的条目的数量。
https://stackoverflow.com/questions/57648377
复制相似问题