在 Julia 中设置多个 I/O 缓冲区的最佳方法是什么?
What is the best way to set up multiple I/O buffers in Julia?
我正在试验在 Julia 中处理长文本字符串(例如书的长度)的不同方法。具体来说,我正在研究转置密码,并一直在使用 (1) 字符串连接、(2) 数组和 (3) I/O 缓冲区测试速度和内存使用情况。在最后一种情况下,我需要能够 'print' 单个字符到不同的、可索引的 I/O 缓冲区。我的第一次(简化)尝试如下:
text = fill(IOBuffer(), 3)
print(text[1], 'a')
print(text[2], 'b')
print(text[3], 'c')
for i in 1:3
println(String(take!(text[i])))
end
这会产生:
"abc"
""
""
换句话说,第一个索引返回整个字符串 "abc"
而不仅仅是所需的字符 'a'
,而其他索引在缓冲区被重置时生成空字符串 ""
在第一个 take!()
函数之后。
我的下一次尝试成功了,但似乎并不复杂:
text = Vector(3)
for i in 1:3
text[i] = IOBuffer()
end
print(text[1], 'a')
print(text[2], 'b')
print(text[3], 'c')
for i in 1:3
println(String(take!(text[i])))
end
这会产生所需的输出:
"a"
"b"
"c"
我仍然不完全确定为什么第一种方法失败而第二种方法有效,但是有谁知道设置多个 I/O 可以使用索引写入的缓冲区的更好方法吗?
你的问题的原因是在 text = fill(IOBuffer(), 3)
中调用 IOBuffer()
只被评估一次,所以 text
的所有条目都指向同一个对象。可以通过运行ning:
查看
julia> all(x->x===text[1], text)
true
或者当你 运行:
时你可以看到这个
julia> fill(println("AAA"), 3)
AAA
3-element Array{Void,1}:
nothing
nothing
nothing
发现 println
仅被调用一次 - 在将其值传递给 fill
方法之前。
解决它的最简单方法是使用理解:
julia> text = [IOBuffer() for i in 1:3]
3-element Array{Base.AbstractIOBuffer{Array{UInt8,1}},1}:
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1)
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1)
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1)
julia> map(x->x===text[1], text)
3-element Array{Bool,1}:
true
false
false
或map
(不太干净):
julia> map(i->IOBuffer(), 1:3)
3-element Array{Base.AbstractIOBuffer{Array{UInt8,1}},1}:
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1)
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1)
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1)
julia> map(x->x===text[1], text)
3-element Array{Bool,1}:
true
false
false
实际上你可以用 IOBuffer
类型和 invoke
类型填充数组(这不是推荐的方法,但会告诉你区别):
julia> text = invoke.(fill(IOBuffer, 3), [Tuple{}])
3-element Array{Base.AbstractIOBuffer{Array{UInt8,1}},1}:
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1)
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1)
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1)
julia> map(x->x===text[1], text)
3-element Array{Bool,1}:
true
false
false
最后,如 here 所述,要记住的一点是推导将为创建的数组的每个条目调用一个函数,但如果您使用宏,它只会被调用一次。这是 link 中详细解释的一个简短示例:
julia> rx = [Regex("a") for i in 1:3]
3-element Array{Regex,1}:
r"a"
r"a"
r"a"
julia> map(x->x===rx[1], rx)
3-element Array{Bool,1}:
true
false
false
julia> rx = [r"a" for i in 1:3]
3-element Array{Regex,1}:
r"a"
r"a"
r"a"
julia> map(x->x===rx[1], rx)
3-element Array{Bool,1}:
true
true
true
我正在试验在 Julia 中处理长文本字符串(例如书的长度)的不同方法。具体来说,我正在研究转置密码,并一直在使用 (1) 字符串连接、(2) 数组和 (3) I/O 缓冲区测试速度和内存使用情况。在最后一种情况下,我需要能够 'print' 单个字符到不同的、可索引的 I/O 缓冲区。我的第一次(简化)尝试如下:
text = fill(IOBuffer(), 3)
print(text[1], 'a')
print(text[2], 'b')
print(text[3], 'c')
for i in 1:3
println(String(take!(text[i])))
end
这会产生:
"abc"
""
""
换句话说,第一个索引返回整个字符串 "abc"
而不仅仅是所需的字符 'a'
,而其他索引在缓冲区被重置时生成空字符串 ""
在第一个 take!()
函数之后。
我的下一次尝试成功了,但似乎并不复杂:
text = Vector(3)
for i in 1:3
text[i] = IOBuffer()
end
print(text[1], 'a')
print(text[2], 'b')
print(text[3], 'c')
for i in 1:3
println(String(take!(text[i])))
end
这会产生所需的输出:
"a"
"b"
"c"
我仍然不完全确定为什么第一种方法失败而第二种方法有效,但是有谁知道设置多个 I/O 可以使用索引写入的缓冲区的更好方法吗?
你的问题的原因是在 text = fill(IOBuffer(), 3)
中调用 IOBuffer()
只被评估一次,所以 text
的所有条目都指向同一个对象。可以通过运行ning:
julia> all(x->x===text[1], text)
true
或者当你 运行:
时你可以看到这个julia> fill(println("AAA"), 3)
AAA
3-element Array{Void,1}:
nothing
nothing
nothing
发现 println
仅被调用一次 - 在将其值传递给 fill
方法之前。
解决它的最简单方法是使用理解:
julia> text = [IOBuffer() for i in 1:3]
3-element Array{Base.AbstractIOBuffer{Array{UInt8,1}},1}:
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1)
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1)
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1)
julia> map(x->x===text[1], text)
3-element Array{Bool,1}:
true
false
false
或map
(不太干净):
julia> map(i->IOBuffer(), 1:3)
3-element Array{Base.AbstractIOBuffer{Array{UInt8,1}},1}:
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1)
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1)
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1)
julia> map(x->x===text[1], text)
3-element Array{Bool,1}:
true
false
false
实际上你可以用 IOBuffer
类型和 invoke
类型填充数组(这不是推荐的方法,但会告诉你区别):
julia> text = invoke.(fill(IOBuffer, 3), [Tuple{}])
3-element Array{Base.AbstractIOBuffer{Array{UInt8,1}},1}:
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1)
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1)
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1)
julia> map(x->x===text[1], text)
3-element Array{Bool,1}:
true
false
false
最后,如 here 所述,要记住的一点是推导将为创建的数组的每个条目调用一个函数,但如果您使用宏,它只会被调用一次。这是 link 中详细解释的一个简短示例:
julia> rx = [Regex("a") for i in 1:3]
3-element Array{Regex,1}:
r"a"
r"a"
r"a"
julia> map(x->x===rx[1], rx)
3-element Array{Bool,1}:
true
false
false
julia> rx = [r"a" for i in 1:3]
3-element Array{Regex,1}:
r"a"
r"a"
r"a"
julia> map(x->x===rx[1], rx)
3-element Array{Bool,1}:
true
true
true