環境
- OS: ArchLinux
- Julia 1.0.1
入出力先を変える
Python だと stdout
を気軽に上書きして標準出力先をファイルにできますが、Julia の場合はそれができません。
julia> f = open("out.txt", "w") IOStream(<file out.txt>) julia> stdout = f ERROR: cannot assign variable Base.stdout from module Main Stacktrace: [1] top-level scope at none:0
標準出力先を変えたい時は redirect_stdout
を使って変更します。
julia> originalstdout = stdout # 元の設定を避難しておく Base.TTY(RawFD(0x0000000d) open, 0 bytes waiting) julia> stdout Base.TTY(RawFD(0x0000000d) open, 0 bytes waiting) julia> (rd, wr) = redirect_stdout() (Base.PipeEndpoint(RawFD(0x00000013) open, 0 bytes waiting), Base.PipeEndpoint(RawFD(0x00000014) open, 0 bytes waiting)) julia> stdout # 指しているところが wr と同じところになった。 Base.PipeEndpoint(RawFD(0x00000014) open, 0 bytes waiting) julia> println("Hello") # print を書いても画面には表示されない julia> println("World") julia> close(wr) julia> data = readavailable(rd) # バッファからデータを取ってくる 12-element Array{UInt8,1}: 0x48 0x65 0x6c 0x6c 0x6f 0x0a 0x57 0x6f 0x72 0x6c 0x64 0x0a julia> close(rd) julia> redirect_stdout(originalstdout) # 標準出力を元に戻す Base.TTY(RawFD(0x0000000d) open, 0 bytes waiting) julia> print(String(data)) Hello World
標準出力先をファイルに変えることも出来ます。
julia> originalstdout = stdout Base.TTY(RawFD(0x0000000d) open, 0 bytes waiting) julia> f = open("out.txt", "w") IOStream(<file out.txt>) julia> redirect_stdout(f) IOStream(<file out.txt>) julia> println("Hello World") julia> close(f) julia> redirect_stdout(originalstdout) Base.TTY(RawFD(0x0000000d) open, 0 bytes waiting) shell> cat out.txt Hello World
標準入力、標準エラー出力についても同じ様に出来ます。
標準入力
shell> cat in.txt 2 4 julia> originalstdin = stdin Base.TTY(RawFD(0x0000000a) paused, 0 bytes waiting) julia> f = open("in.txt", "r") IOStream(<file in.txt>) julia> redirect_stdin(f) IOStream(<file in.txt>) julia> n, m = parse.(Int, split(readline())) # キーボードから入力せずとも勝手にファイルから読み込んでくる 2-element Array{Int64,1}: 2 4 julia> println(n * m) 8 julia> close(f) julia> redirect_stdin(originalstdin) Base.TTY(RawFD(0x0000000a) paused, 0 bytes waiting)
標準エラー
julia> originalstderr = stderr Base.TTY(RawFD(0x0000000f) open, 0 bytes waiting) julia> f = open("out.txt", "w") IOStream(<file out.txt>) julia> redirect_stderr(f) IOStream(<file out.txt>) julia> println(stderr, "STDERR") julia> close(f) julia> redirect_stderr(originalstderr) Base.TTY(RawFD(0x0000000f) open, 0 bytes waiting) shell> cat out.txt STDERR
Julia のソースコードを見る限り、元の標準出力等に戻すには上記の originalstdout
のように自力で避難しておくしか方法はなさそうです。ちょっと不便。
使いどころ(?)
SHELL で
$ julia ex.jl < in.txt > out.txt
として動かしていたプログラムを run
を使わずに Julia から実行できるようになります。
in.txt
2 4
gcd.jl
x, y = parse.(Int, split(readline())) mygcd(x,y) = y == 0 ? x : mygcd(y, mod(x,y)) println(mygcd(x,y))
プログラムを実行するための関数
function run_file(input_filename::String, output_filename::String, filename::String) originalstdin = stdin originalstdout = stdout fin = open(input_filename, "r") redirect_stdin(fin) fout = open(output_filename, "w") redirect_stdout(fout) include(filename) close(fin) close(fout) redirect_stdout(originalstdout) redirect_stdin(originalstdin) end
julia> @time run(pipeline(`julia gcd.jl`, stdin="in.txt", stdout="out.txt")); 0.666613 seconds (394.68 k allocations: 20.278 MiB) julia> @time run(pipeline(`julia gcd.jl`, stdin="in.txt", stdout="out.txt")); 0.406997 seconds (65 allocations: 2.656 KiB) julia> @time run(pipeline(`julia gcd.jl`, stdin="in.txt", stdout="out.txt")); 0.413124 seconds (65 allocations: 2.656 KiB) julia> @time run_file("in.txt", "out.txt", "gcd.jl"); 0.239453 seconds (392.67 k allocations: 20.973 MiB) julia> @time run_file("in.txt", "out.txt", "gcd.jl"); 0.031852 seconds (18.40 k allocations: 972.514 KiB, 20.19% gc time) julia> @time run_file("in.txt", "out.txt", "gcd.jl"); 0.026645 seconds (18.40 k allocations: 972.482 KiB)
run
を使った方法よりも実行時間は大分改善されます。(メモリは大分消費するようですが。)
競技プログラミングでの Julia の実行時間の計測方法の改善に応用できないかなと思ったのですが、システムを構築するのがとても面倒そうだなと思いました。