Я копался в алгоритмах управления памятью Python и лежал в основе кода C и проверял, как он работает, получая неожиданный результат.
База
Создайте строку 5,5 ГБ на виртуальной машине CentOS с ОЗУ 6 ГБ, используя несколько методов. Генерация осуществляется через диктовку, в которой говорится, сколько раз должны появиться символы, отсортированные (например, {3: 5, 1: 3}
должно давать «11133333»).
Expectation :
''.join()
должно работать, потому что он использует memcpy (), и максимум, который он будет использовать, является частью строки плюс следующая часть итерируемой. Хотя он создает буфер, объекты dict
хорошо работают с swap. Гранулирование пользовательской итерации может сделать компромисс между скоростью и использованием памяти.
''.format()
фактически освобождает память, поэтому она должна работать быстрее и лучше.
s1+=s2
должен быть максимально загружен памятью, поскольку он будет хранить обе строки в памяти и создавать буфер для новой.
Результат
С MemoryError все не работает, кроме:
- ''.join()
с минимальной грануляцией
- ... конкатенация.
python -m dis pymemory.py
показал мне «INPLACE_ADD» для операции конкатенации, которая не совпадает с кодом C, на который я смотрел.
Код
Код немного урезан, очевидно, все методы должны запускаться отдельно.
b = {
0: 590615000,
1: 591234001,
2: 590895000,
3: 590010000,
4: 591552000,
5: 590375000,
6: 589251000,
7: 589903000,
8: 590806000,
9: 590939000
}
# literal format
a = '{}{}{}{}{}{}{}{}{}{}'.format(str(0)*b[0], str(1)*b[1], str(2)*b[2], str(3)*b[3], str(4)*b[4], str(5)*b[5], str(6)*b[6], str(7)*b[7], str(8)*b[8], str(9)*b[9])
del a
# format
# MEMORY ERROR
d = {}
for k in b:
d['k'+str(k)] = str(k)*b[k]
a = ('{}'*d.keys().__len__()).format(*['{'+str(k)+'}' for k in sorted(d.keys())]).format(**d)
del a
del d
# join
# MEM ERROR
def i_am_iter(d):
for k in d:
yield str(k)*d[k]
raise StopIteration
a = ''.join(i_am_iter(b))
# concat
# WORKS!
a = ''
for k in b:
a += str(k)*b[k]
Вопрос
Есть ли объяснение этому? Почему конкатенация работает? Почему не присоединяется или не форматирует? Есть ли оптимизация, которую я где-то упускаю?