Пишите в несколько файлов одновременно на Юлии - PullRequest
0 голосов
/ 25 октября 2018

Как мне распечатать несколько файлов одновременно в Julia?Есть ли более чистый способ, кроме:

for f in [open("file1.txt", "w"), open("file2.txt", "w")]
    write(f, "content")
    close(f)
end

Ответы [ 3 ]

0 голосов
/ 25 октября 2018

Если вы действительно хотите писать параллельно (используя несколько процессов), вы можете сделать это следующим образом:

using Distributed
addprocs(4) # using, say, 4 examples

function ppwrite()
    @sync @distributed for i in 1:10
        open("file$(i).txt", "w") do f
            write(f, "content")
        end
    end
end

Для сравнения, последовательная версия будет

function swrite()
    for i in 1:10
        open("file$(i).txt", "w") do f
            write(f, "content")
        end
    end
end

Вкл.на моей машине (ssd + quadcore) это приводит к ускорению на ~ 70%:

julia> @btime ppwrite();
  3.586 ms (505 allocations: 25.56 KiB)

julia> @btime swrite();
  6.066 ms (90 allocations: 6.41 KiB)

Однако имейте в виду, что эти временные характеристики могут кардинально измениться для реального контента, который, возможно, придется перенести в другие процессы.Кроме того, они, вероятно, не будут масштабироваться, поскольку IO, как правило, является узким местом в какой-то момент.

Обновление: более крупный (строковый) контент

julia> using Distributed, Random, BenchmarkTools

julia> addprocs(4);

julia> global const content = [string(rand(1000,1000)) for _ in 1:10];

julia> function ppwrite()
           @sync @distributed for i in 1:10
               open("file$(i).txt", "w") do f
                   write(f, content[i])
               end
           end
       end
ppwrite (generic function with 1 method)

julia> function swrite()
           for i in 1:10
               open("file$(i).txt", "w") do f
                   write(f, content[i])
               end
           end
       end
swrite (generic function with 1 method)

julia> @btime swrite()
  63.024 ms (110 allocations: 6.72 KiB)

julia> @btime ppwrite()
  23.464 ms (509 allocations: 25.63 KiB) # ~ 2.7x speedup

Делать то же самоесо строковыми представлениями больших матриц 10000x10000 (3 вместо 10) приводит к

julia> @time swrite()
  7.189072 seconds (23.60 k allocations: 1.208 MiB)

julia> @time swrite()
  7.293704 seconds (37 allocations: 2.172 KiB)

julia> @time ppwrite();
 16.818494 seconds (2.53 M allocations: 127.230 MiB) # > 2x slowdown of first call

julia> @time ppwrite(); # 30%$ slowdown of second call
  9.729389 seconds (556 allocations: 35.453 KiB)
0 голосов
/ 26 октября 2018

Просто чтобы добавить версию сопрограммы, которая выполняет IO параллельно, как многопроцессорная, но также избегает дублирования и передачи данных.

julia> using Distributed, Random

julia> global const content = [randstring(10^8) for _ in 1:10];

julia> function swrite()
           for i in 1:10
               open("file$(i).txt", "w") do f
                   write(f, content[i])
               end
           end
       end
swrite (generic function with 1 method)

julia> @time swrite()
  1.339323 seconds (23.68 k allocations: 1.212 MiB)

julia> @time swrite()
  1.876770 seconds (114 allocations: 6.875 KiB)

julia> function awrite()
           @sync for i in 1:10
               @async open("file$(i).txt", "w") do f
                   write(f, "content")
               end
           end
       end
awrite (generic function with 1 method)

julia> @time awrite()
  0.243275 seconds (155.80 k allocations: 7.465 MiB)

julia> @time awrite()
  0.001744 seconds (144 allocations: 14.188 KiB)

julia> addprocs(4)
4-element Array{Int64,1}:
 2
 3
 4
 5

julia> function ppwrite()
           @sync @distributed for i in 1:10
               open("file$(i).txt", "w") do f
                   write(f, "content")
               end
           end
       end
ppwrite (generic function with 1 method)

julia> @time ppwrite()
  1.806847 seconds (2.46 M allocations: 123.896 MiB, 1.74% gc time)
Task (done) @0x00007f23fa2a8010

julia> @time ppwrite()
  0.062830 seconds (5.54 k allocations: 289.161 KiB)
Task (done) @0x00007f23f8734010
0 голосов
/ 25 октября 2018

Исходя из вашего вопроса, я предполагаю, что вы не имеете в виду запись параллельно (что, вероятно, не ускорит процесс из-за того, что операция, вероятно, связана с IO).

ВашРешение имеет одну маленькую проблему - оно не гарантирует, что f будет закрыто, если write выдает исключение.

Вот три альтернативных способа сделать это, чтобы убедиться, что файл закрыт даже при ошибке:

for fname in ["file1.txt", "file2.txt"]
    open(fname, "w") do f
        write(f, "content")
    end
end

for fname in ["file1.txt", "file2.txt"]
    open(f -> write(f, "content"), fname, "w")
end

foreach(fn -> open(f -> write(f, "content"), fn, "w"),
        ["file1.txt", "file2.txt"])

Они дают одинаковый результат, поэтому выбор является делом вкуса (вы можете получить еще несколько вариантов аналогичных реализаций).

Все методы основаны на следующем методе open function:

 open(f::Function, args...; kwargs....)

  Apply the function f to the result of open(args...; kwargs...)
  and close the resulting file descriptor upon completion.

Заметьте, что обработка все равно будет прекращена, если где-то фактически возникнет исключение (гарантируется, что дескриптор файла будет закрыт).Чтобы убедиться, что каждая операция записи действительно выполняется, вы можете сделать что-то вроде:

for fname in ["file1.txt", "file2.txt"]
    try
        open(fname, "w") do f
            write(f, "content")
        end
    catch ex
        # here decide what should happen on error
        # you might want to investigate the value of ex here
    end
end

См. https://docs.julialang.org/en/latest/manual/control-flow/#The-try/catch-statement-1 для документации try/catch.

...