sqlite 这个协程在写入通道时真的是非阻塞的吗?

bhmjp9jg  于 2023-05-18  发布在  SQLite
关注(0)|答案(1)|浏览(143)

我一直在尝试将一个blob从SQLite数据库传递到浏览器,而不必先将blob写入内存,也不必阻塞Tcl脚本。显然,chan copy-command可以解决这个问题(我用一个文件试过,它没有阻塞),但是这个特性不能用SQLite的incrblob
我尝试了几种方法来解决这个问题,大多数都远远超出了我的技能水平,也许是完全错误的方法。我再次阅读了关于协程的文章,看到了一个使用Tcllib coroutine:util的例子,我想知道如果没有它,我是否可以做类似的事情。
下面的代码将blob(一个250 MB的视频文件)传递给浏览器,因为它的$sock通道有一个可写事件。它的工作原理是,视频播放,每30秒左右,事件似乎火和更多的数据被复制。
我意识到blob在写入out通道之前最终仍被复制到内存;但是它是基于在每个chan puts中传递的大小的小块。
我的问题是:
1.这种做法合理吗?它位于桌面应用程序的最小本地服务器中。
1.现在真的不堵了吗?测试起来相当困难,因为来自浏览器的新请求很小,复制的时间很短,因此没有时间尝试同时触发另一个进程。这本身就是解决阻塞问题的一种方法:仅仅在很短时间间隔内阻塞,其不明显。但我还是想知道。两个通道都设置为-blocking 0,我认为协程应该帮助它不阻塞;但我不完全理解,除了它将控制权交还给调用者这一事实之外,在本例中,调用者是一个没有剩余语句可执行的过程。我认为这意味着不需要在协程中使用after 0 []方法。
1.有人知道incrblob的问题吗?是不是它的通道属于不同的解释器,使得事件没有到达正确的“位置”?
谢谢你考虑我的问题。

proc ::REQ::SendBLOB {sock filename type id} {
  dbws eval {select rowid, length(col_blob) as bytes from db.table where id=:id} {
    # Get the BLOB as a (read-only) channel
    set fp [dbws incrblob -readonly db table col_blob $rowid]
    chan configure $fp -translation binary -blocking 0
    chan configure $sock -translation binary -blocking 0
    # Would use chan copy with -command but it will not work with incrblob.
    # chan copy $fp $sock -size $bytes -command [list ::REQ::ChanCopyCleanup $fp]
  }
  coroutine ::coro_incrblob${sock} proxyfcopy $fp $sock $bytes
  chan event $sock writable ::coro_incrblob${sock}
}

proc proxyfcopy {fp sock bytes} {
  while { ![chan eof $fp] } {
    yield
    # Think this 4096 should be at least 5,120,000; for it appears
    # that Firefox requests 60 MB at first load and 5 MB thereafter.
    if { $bytes > 4096 } {
      set size 4096
    } elseif { $bytes > 0 } {
      set size $bytes
    } else {
      chan event $sock writable {}
      close $fp
      return
    }
    set data [read $fp $size]
    chan puts stdout $bytes
    chan puts -nonewline $sock $data
    set bytes [expr {$bytes - [string length $data]}]
  }
}
1wnzp6jl

1wnzp6jl1#

incrblob通道不支持无阻塞操作;它们的底层通道描述符没有关闭阻塞模式的方法(通道类型的C类型记录中的字段是NULL)。然而,对blob的写入无论如何都会非常快,因为它们肯定不涉及空间的重新分配-增量blob访问机制不能改变blob的大小-或提交事务(在自动提交模式下,提交发生在您关闭通道时;否则,当你明确地COMMIT时,当然会发生)。这有点像处理标准文件;这些 * 技术上 * 允许你设置非阻塞模式,但这样做没有意义,因为操作系统实际上忽略了这种情况下的标志(或者更确切地说,它更像是所有文件都是非阻塞的,除非在联网的文件系统上,因为联网的文件系统有奇怪的语义,你无论如何都会被阻塞)。对于只读的incrblob通道,一旦数据库设置好了,它们将从内存中有效地得到满足,因此非常非常快。
因为你也在处理网络套接字,* 那些 * 支持真正的非阻塞模式。特别地,当套接字的OS级输出缓冲区未满时,套接字是可写的。
chan copy实现要求读端为非阻塞异步操作。在这里不能这样做,但是仍然可以使用同步chan copy来避免在Tcl运行时的更高级别中复制数据。如果你使用固定的传输(1444可能是一个很好的猜测-这是一个1500以太网MTU减去54字节的以太网头,IP头和TCP头的开销,四舍五入到一个字的大小-但更大的可能也是好的,因为你最终处理流模型时,做TCP和操作系统确实为你做一些事情;你需要测量),那么你应该得到合理的效率。每当输出通道可写时,移动其中一个。

相关问题