Как уже указывалось в комментариях, вы не должны ожидать, что cython ускорит ваш код, потому что большую часть времени алгоритм тратит на itertools и создание списков.
Поскольку мне любопытно посмотреть, как общая реализация реализации itertools
против уловок старой школы, давайте посмотрим на реализацию Cython "все подмножества k из n":
%%cython
ctypedef unsigned long long ull
cdef ull next_subset(ull subset):
cdef ull smallest, ripple, ones
smallest = subset& -subset
ripple = subset + smallest
ones = subset ^ ripple
ones = (ones >> 2)//smallest
subset= ripple | ones
return subset
cdef subset2list(ull subset, int offset, int cnt):
cdef list lst=[0]*cnt #pre-allocate
cdef int current=0;
cdef int index=0
while subset>0:
if((subset&1)!=0):
lst[index]=offset+current
index+=1
subset>>=1
current+=1
return lst
def all_k_subsets(int start, int end, int k):
cdef int n=end-start
cdef ull MAX=1L<<n;
cdef ull subset=(1L<<k)-1L;
lst=[]
while(MAX>subset):
lst.append(subset2list(subset, start, k))
subset=next_subset(subset)
return lst
Эта реализация использует некоторые хорошо известные трюки и имеет ограничение, заключающееся в том, что она работает не более чем с 64 элементами.
Если мы сравним оба подхода:
>>> %timeit x(1,45,6)
2.52 s ± 108 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit all_k_subsets(1,45,6)
1.29 s ± 5.16 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Ускорение фактора 2 весьма разочаровывает.
Однако узким местом является создание списков, а не сам расчет - легко проверить, что без создания списка расчет займет около 0,1 секунды.
Мой вывод: если вы серьезно относитесь к скорости, вам не следует создавать так много списков, а выполнять подмножество на лету (лучшее в Cython) - возможно ускорение более чем на 10. Если необходимо иметь все подмножества в виде списков, то вы не можете ожидать значительного ускорения.