io - 在 Julia 中设置多个 I/O 缓冲区的最佳方法是什么?

标签 io buffer julia

我正在尝试在 Julia 中处理长文本字符串(例如书籍长度)的不同方法。具体来说,我正在研究转置密码,并使用 (1) 字符串连接、(2) 数组和 (3) I/O 缓冲区来测试速度和内存使用情况。在最后一种情况下,我需要能够将单个字符“打印”到不同的可索引 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 指向同一个对象。您可以通过运行来检查:

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 类型填充数组并调用它们(这不是推荐的方法,但会向您展示差异):

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 ,是理解式将为创建的数组的每个条目调用一个函数,但如果您使用宏,则只会调用一次。这是链接中详细解释的一个简短示例:

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

关于io - 在 Julia 中设置多个 I/O 缓冲区的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49533361/

相关文章:

java - 缓冲流在 Java 内部是如何工作的

c++ - 网络编程问题 - 缓冲区只会向服务器发送一次

julia - 错误: `*` 没有方法匹配 *(::Variable)

julia - Julia 中推荐的数据结构以实现高效追加

python - PyCall import ("numpy") 产生 MKL FATAL ERROR

Haskell:不同语言的实际 IO monad 实现?

linux - zLib透明写入模式 "wT"性能下降

删除一行的 C 代码

java - AsynchronousSocketChannel Read/WritePendingException - 可以同步吗?

c++ - Directx 访问后台缓冲区