Как продолжение до этого вопроса Я пытаюсь обойти построение списка, примером которого является range(int(1e8))
, с помощью генератора xrange(int(1e8))
. Где xrange
- это просто пример для процесса, который выдает длинную последовательность значений. (Пожалуйста, предположите, что это не может быть легко воспроизведено.) Еще один фон, у меня есть длинный список пар меток времени / значений, над которыми я хочу провести некоторую обработку (вроде временных рядов). Я стараюсь не вытягивать их в память в целом, потому что это много данных.
Я подумал, что было бы здорово, если бы я мог применить несколько блоков обработки одновременно к этому потоку данных, генерируемых моим генератором. Первой идеей было использование itertools.tee()
, например ::
from itertools import tee
g1,g2 = tee(xrange(int(1e8)),2)
sum(g1), sum(g2)
Но потом я обнаружил, что только первый sum()
будет использовать генератор, в то время как tee()
снова создаст list
(чего я хотел избежать.)
Поэтому я подумал, что мне нужно асинхронное решение, то есть такое, которое позволило бы каждому sum()
обновлять каждый шаг генератора.
Вещи, которые пришли в голову, где
Но я никогда не использовал их раньше, и отчасти я даже не могу сказать, могут ли подходы работать или быть эффективными / действенными / эффективными.
С этого момента я с удовольствием буду рад любым предложениям из зала!
Обновление
Я хотел бы избежать решения на основе обратного вызова , так как оно значительно снижает производительность (именно так оно и реализуется в настоящее время). Я добавил некоторые профилирования ниже (пожалуйста, добавьте комментарии, если тест не является объективным):
class SinkA:
def __init__(self, src):
for i in src: pass
class SinkB:
def f(self,i):
pass
class Source:
def __iter__(self):
for i in xrange(int(1e4)):
yield i
def t1():
src = Source()
snk = SinkA(src)
def t2():
src = Source()
snk = SinkB()
for i in src: snk.f(i)
if __name__ == "__main__":
from timeit import Timer
n = 1000
t = Timer("t1()", "from __main__ import t1, t2, SinkA, SinkB, Source")
print "%.2f usec/pass" % (1000000 * t.timeit(number=n)/n) # 612.11 usec/pass
t = Timer("t2()", "from __main__ import t1, t2, SinkA, SinkB, Source")
print "%.2f usec/pass" % (1000000 * t.timeit(number=n)/n) # 1933.39 usec/pass
Обновление 2
Что еще я могу сказать? У меня есть это решение на основе обратного вызова, которое кажется неэффективным. Подход на основе генератора кажется многообещающим, но у меня слишком мало опыта в такого рода программировании, особенно когда речь идет о более сложных вещах, таких как сопрограммы или искаженная библиотека.
Подводя итог, у меня есть несколько потребителей для процесса, который генерирует много данных, и я определил некоторые потенциальные подходы. Сейчас я ищу квалифицированные заявления опытных пользователей, которые, вероятно, уже выполняли аналогичные задачи. Заявления о том, какой подход может быть подходящим, как эти подходы связаны друг с другом. Или какие другие подходы я мог бы пропустить в конце концов.