与OCaml Async同时写入

时间:2017-07-18 07:39:58

标签: asynchronous ocaml core

我正在从网络上读取数据,而且每当我拿到它时,我都想把它写到文件中。写入是并发和非顺序的(想想P2P文件共享)。在C中,我将获得文件的文件描述符(在程序的持续时间内)然后使用this.componentRootDOM,然后使用lseek并最终关闭write。这些操作可以在多线程设置中由互斥锁保护(尤其是lseek和write应该是原子的)。

我真的不知道如何在Async中获得这种行为。我最初的想法就是拥有这样的东西。

fd

然后,在接收数据时异步调度写入。

我的解决方案并不正确。首先,这个 let write fd s pos = let posl = Int64.of_int pos in Async_unix.Unix_syscalls.lseek fd ~mode:`Set posl >>| fun _ -> let wr = Writer.create t.fd in let len = String.length s in Writer.write wr s ~pos:0 ~len 任务需要是原子的,但事实并非如此,因为可以在第一个write之前执行两个lseek。即使我可以按顺序安排Writer.write,但由于write没有返回Writer.write,因此无法提供帮助。有什么想法吗?

顺便说一句,这是之前回答question的后续行动。

1 个答案:

答案 0 :(得分:2)

基本方法是拥有一个工作队列,每个工作人员执行原子seek/write 1 操作。不变量是一次只有一个工人在运行。更复杂的策略将采用优先级队列,其中写入由一些最大化吞吐量的标准排序,例如,写入后续位置。如果你观察到很多小写,你也可以实现复杂的缓冲策略,然后一个好主意就是将它们合并成更大的块。

但是,让我们从一个简单的非优先级队列开始,通过Async.Pipe.t实现。对于位置写入,我们不能使用Writer接口,因为它是为缓冲顺序写入而设计的。因此,我们将使用来自Unix.lseek和Bigstring.really_write Async_unix.Std Fd.syscall_in_thread`函数的function. The really_write is a regular non-asynchronous function, so we need to lift it into the Async interface using the,例如,

let really_pwrite fd offset bytes = 
  Unix.lseek fd offset ~mode:`Set >>= fun (_ : int64) ->
  Fd.syscall_in_thread fd (fun desc -> 
    Bigstring.really_write desc bytes)

注意:此函数将写入系统决定的字节数,但不超过bytes的长度。因此,您可能对实现将写入所有字节的really_pwrite函数感兴趣。

整个方案将包括一个主线程,它将拥有一个文件描述符,并通过Async.Pipe接受来自多个客户端的写请求。假设每个写请求都是以下类型的消息:

 type chunk = {
    offset : int;
    bytes : Bigstring.t;
 }

然后您的主线程将如下所示:

let process_requests fd = 
  Async.Pipe.iter ~f:(fun {offset; bytes} -> 
    really_pwrite fd offset bytes)

really_pwrite是一个真正写入所有字节并处理所有错误的函数。在实际执行Async.Pipe.iter'系统调用之前,您还可以使用pwrite函数并预先编程并合并写入。

还有一个优化说明。分配大字符串是一项相当昂贵的操作,因此您可以考虑预先分配一个大的大字符串并从中提供小块。这将创建有限的资源,因此您的客户将等到其他客户端完成其写入并释放其块。因此,您将拥有一个内存占用有限的受限制系统。

1)理想情况下我们应该使用pwrite尽管Janestreet仅提供pwrite_assume_fd_is_nonblocking函数,但在调用系统{{1}时不会释放OCaml运行时已完成,并将实际阻止整个系统。所以我们需要使用搜索和写入的组合。后者将释放OCaml运行时,以便程序的其余部分可以继续。 (另外,鉴于他们对非阻塞fd的定义,这个功能并没有多大意义,因为只有套接字和FIFO被认为是非阻塞的,据我所知,它们不支持搜索操作。我会在他们的bug跟踪器上提出问题。