【问题标题】:Is uv_write actually asynchronous?uv_write 实际上是异步的吗?
【发布时间】:2017-11-20 22:01:05
【问题描述】:

根据tutorial for libuv,对uv_write 的后续调用不应导致一个写入阻塞另一个写入(我的理解是它们应该发生在不同的线程上)。
但是我已经在strace 下运行了示例代码,但似乎情况并非如此。使用uv_fs_write 运行类似示例后,我可以看到每个写入调用都发生在单独的线程上并且不会阻塞。

有人可以解释uv_write 的预期行为是什么,以及当底层流是文件句柄时它是否应该与uv_fs_write 不同?

cat Makefile | strace ./uvtee/uvtee ~/out.txt

open("/home/james/out.txt", O_RDWR|O_CREAT|O_CLOEXEC, 0644) = 11
ioctl(11, FIONBIO, [1])                 = 0
epoll_ctl(6, EPOLL_CTL_ADD, 7, {EPOLLIN, {u32=7, u64=7}}) = 0
epoll_ctl(6, EPOLL_CTL_ADD, 9, {EPOLLIN, {u32=9, u64=9}}) = 0
epoll_ctl(6, EPOLL_CTL_ADD, 0, {EPOLLIN, {u32=0, u64=0}}) = 0
epoll_wait(6, [{EPOLLIN|EPOLLHUP, {u32=0, u64=0}}], 1024, -1) = 1
brk(0xb3e000)                           = 0xb3e000
read(0, "examples=\\\n\thelloworld\\\n\tidle-ba"..., 65536) = 1965
write(1, "examples=\\\n\thelloworld\\\n\tidle-ba"..., 1965) = 1965
write(11, "examples=\\\n\thelloworld\\\n\tidle-ba"..., 1965) = 1965

完整代码可以在here找到。

【问题讨论】:

  • 我已经修好了。希望现在更清楚一点。
  • 您确定您链接到的示例是相关示例吗?似乎将文件视为管道,它在引用常规文件的文件描述符上调用 uv_pipe_open() - 这似乎绕过了您的问题。
  • 对不起,示例使用管道来抽象文件句柄。我真正想知道的是,它是否期望使用管道处理文件并调用 uv_write 与使用 uv_fs_write 有不同的行为?似乎在 uv_fs_write 中为写入生成了一个线程,而 uv_write 在同一线程上进行了顺序调用。
  • 如果你从表面上看文档,它说对于某些类型(例如管道),写入不是在单独的线程中完成的(因为管道可以集成到事件循环中),而对于文件/使用 uv_fs_write 时,操作发生在单独的线程中。即是的,您正在看到预期的行为。也就是说,libuv 的设计可能不会假设您应该对 libuv 撒谎并将引用文件的描述符与管道连接 - uv_pipe_open() 的文档甚至说“但它要求它代表一个有效的管道。”。所以没有保证的行为。

标签: c linux asynchronous strace libuv


【解决方案1】:

fs 操作在线程池上运行。这是因为没有良好且可移植的方法来为文件执行非阻塞 IO。因为我们使用了线程池,所以写操作确实可以并行运行。这就是为什么 uv_fs_write 需要一个偏移量参数,所以多个线程可以写入而不会相互叠加。

一个值得注意的例外是 macOS,它使用全局锁来序列化 uv_fs_write 操作。

现在,网络 IO 完全不同了。我们使用事件循环(如您所知)并且写入操作是排队的,因此它们将按照发送顺序以及底层套接字可写时写入。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-14
    • 2017-08-16
    • 1970-01-01
    • 2021-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多