Почему нарезка по одному символу для строк, отличных от ASCII, выполняется медленнее? - PullRequest
1 голос
/ 13 июля 2020

Рассмотрим следующий код:

n = 10000000
s1 = 'a' + 'α' * n + 'α' + 'a'
s2 = 'a' + 'a' * n + 'a' + 'a'

Итак, s1 содержит символы, отличные от ASCII, а s2 содержит строго 7-битные символы ASCII.

Теперь s1 почти вдвое больше, чем s2:

import sys


print(sys.getsizeof(s1), sys.getsizeof(s2))
# 20000080 10000052

Если бы кто-то произвел нарезку с теми же индексами на этих двух строках (одинаковой длины), это не удивительно, что для s1 это медленнее, так как вокруг копируется больше данных.

Что меня удивило, так это то, что если кто-то попытается получить первый и последний элемент (которые являются 7-битными ASCII в обоих), получается (немного) худшая производительность на s1:

m = 200
%timeit [s1[-1] for _ in range(m)]
# 100000 loops, best of 3: 11.4 µs per loop
%timeit [s2[-1] for _ in range(m)]
# 100000 loops, best of 3: 10.3 µs per loop

%timeit [s1[0] for _ in range(m)]
# 100000 loops, best of 3: 11 µs per loop
%timeit [s2[0] for _ in range(m)]
# 100000 loops, best of 3: 9.89 µs per loop

Я нахожу результат последнего теста особенно удивительным, потому что мне кажется, что можно обойтись смещением массива в в обоих случаях, и не вижу причин для s2 быстрее.

РЕДАКТИРОВАТЬ: для решения проблем, связанных со сроками. Вот что я получаю для нарезки одного символа без создания list:

%timeit s1[-1]
# 10000000 loops, best of 3: 40.6 ns per loop
%timeit s2[-1]
# 10000000 loops, best of 3: 34.5 ns per loop

%timeit s1[0]
# 10000000 loops, best of 3: 38.3 ns per loop
%timeit s2[0]
# 10000000 loops, best of 3: 33.1 ns per loop
...