Чтение cmd для потоковой передачи в BSON в Julia

#io #julia #buffer

#io #julia #буфер

Вопрос:

У меня есть команда curl, ввод которой я хочу загрузить с помощью BSON. По соображениям производительности я хочу прочитать вывод curl непосредственно в память, не сохраняя его в файл. Кроме того, я хочу закрыть curl как можно скорее, поэтому я хочу прочитать данные из curl, а затем передать их в BSON, у нас были некоторые проблемы, когда curl был открыт, потому что это было быстрее, чем последовательный синтаксический анализ.

Я знаю, что это работает, но он слишком долго держит curl открытым, что вызывает проблемы, когда мы делаем это параллельно много раз одновременно, а сервер, с которого мы загружаем, немного занят.

 using BSON
cmd = `curl <some data>`
BSON.load(open(cmd))
  

Чтобы закрыть cmd как можно скорее, у меня есть это:

 # created IOBuffer to wrap bytes
import BSON.load
function BSON.load(bytes::Vector{UInt8})
    io = IOBuffer()
    write(io, bytes)
    seekstart(io)
    BSON.load(io)
end
cmd = `curl <some data>`
BSON.load(read(cmd))
  

что работает, но я считаю это очень уродливым. Также я не уверен, что это не приводит к некоторому снижению производительности.

Есть ли более элегантный способ сделать это? Могу ли я read(cmd) ввести некоторую структуру ввода-вывода, которая затем может быть передана BSON.load ?

Я понял, что точно такая же проблема имеет место для Serialization.deserialize . Мое решение для десериализации такое же, но я приветствую любые улучшения.

Комментарии:

1. Когда вы говорите «но он слишком долго держит curl открытым, что вызывает проблемы, когда мы делаем это параллельно много раз одновременно, а сервер, с которого мы загружаем, немного занят», вы имеете в виду, что BSON.load работает медленнее, чем загрузка, поэтому он блокирует процесс загрузки?

2. Да, точно. Но в основном это происходило во время JSON.parse, где разбор json занимал больше времени, чем загрузка через curl. У нас есть хранилище объектов, которое находится в том же центре обработки данных, что и сервер с Julia, так что это довольно быстро.

Ответ №1:

Немного неясно, что означает ваш вопрос, когда вы говорите, что он «слишком долго держит curl открытым», но вот два разных способа сделать это:

 julia> using BSON

julia> url = "https://raw.githubusercontent.com/JuliaIO/BSON.jl/master/test/test.bson"
"https://raw.githubusercontent.com/JuliaIO/BSON.jl/master/test/test.bson"

julia> open(BSON.load, `curl -s $url`)
Dict{Symbol,Any} with 2 entries:
  :a => Complex{Int64}[1 2im, 3 4im]
  :b => "Hello, World!"

julia> BSON.load(IOBuffer(read(`curl -s $url`)))
Dict{Symbol,Any} with 2 entries:
  :a => Complex{Int64}[1 2im, 3 4im]
  :b => "Hello, World!"
  

Первая версия похожа на вашу первую версию, но сразу же закрывает процесс curl после завершения загрузки. Вторая версия считывает результат вызова curl в байтовый вектор, обертывает его в IOBuffer и затем вызывает BSON.load для этого.

Комментарии:

1. О, open(BSON.load, curl -s $ url ) немедленно закрывается? Это здорово. Просто чтобы быть уверенным, есть ли это где-нибудь в документах? Мне было трудно понять, когда процесс остается открытым до тех пор, пока не будет прочитан весь буфер, и когда он немедленно закрывается.

2. Ну, он закрывается сразу после BSON.load завершения. В общем случае open(f, path) вызывает f дескриптор открытого файла, а затем закрывается, независимо от того, f возвращает или выдает ошибки. Это первый документированный метод, open если вы это сделаете ?open .

3. Да, у нас были проблемы с зависанием curl, когда после него выполнялся последовательный синтаксический анализ, подобный этому, и иногда соединение прерывалось до завершения синтаксического анализа.

4. В этом случае вам, вероятно, понадобится второй, поскольку он сразу считывает все данные в вектор, а затем оборачивает этот вектор в интерфейсе ввода-вывода, чтобы передать его в код синтаксического анализа.

5. Да, точно, я использовал второе решение, и оно решило большинство этих неясных проблем.