В памяти преобразовать поток в Ruby?
Здесь разработчик Node.js, который должен работать с Ruby, так что я довольно плохо знаком со многими концепциями в Ruby и могу воспользоваться некоторой помощью.
Мой вариант использования заключается в том, что мне нужно загрузить очень большие JSON-файлы с разделителями новой строки из S3, преобразовать данные и вернуть их в S3, все в памяти, ничего не записывая на диск.
В Node я могу сделать что-то вроде этого:
s3DownloadStream('my-file').pipe(transformStream).pipe(backToS3Stream)
который преобразует объекты на лету, когда они входят, и помещает их в S3 одновременно.
У меня проблемы с поиском хорошего плана действий для достижения такого же поведения в Ruby. Я видел IO.pipe и Celluloid::IO как возможные варианты, но они все еще не выглядят так, как будто они смогут это сделать.
1 ответ
Ruby не имеет прямого аналога потоков в Node, но у него есть итераторная структура Enumerable, и благодаря этому есть Lazy
вариант. Ленивый перечислитель - это тот, который генерирует данные только по мере необходимости, в отличие от других, которые будут запускаться до завершения каждый раз.
Если вы установите ленивую цепочку, она будет оценивать постепенно, а не все сразу.
Итак, ваш код будет выглядеть так:
s3_download('my-file').lazy.map do |...|
# transform stream
end.each do |...|
# pipe back to S3
end
Вот тривиальный пример, на котором вы можете построить:
input = ('a'..'z')
input.lazy.map do |i|
puts 'i=%s' % i
i.upcase
end.each do |j|
puts ' j=%s' % j
end
Вы можете видеть, как каждое значение проходит через цепочку в отдельности. Если вы удалите lazy
это не так, первый цикл запускается до конца, буферизуется в массив, а затем запускается второй и обрабатывает его также до завершения.
Потоки узлов намного сложнее, чем они, они могут делать такие вещи, как пауза / возобновление, отложить операцию без блокировки и т. Д., Так что с точки зрения функциональности перекрытие очень велико. Ruby может сделать это, если вы потратите время на использование таких вещей, как волокна и нити, но это много работы.