【问题标题】:Is OCaml suitable to write networking servers?OCaml 适合编写网络服务器吗?
【发布时间】:2010-07-14 10:00:10
【问题描述】:

我想知道在多线程环境中通过 TCP 处理典型的客户端/服务器交互时,OCaml 是否会在性能和易于实现方面表现良好。我的意思是非常典型的事情,比如每个客户端都有一个线程来接收数据,对游戏状态进行操作更改并将其发送回客户端。

这是因为我需要为游戏编写服务器,而且我总是用 C 语言做这些事情,但自从现在我知道了 OCaml,我很想知道它是否可以,或者我会发现自己试图解决一个典型的问题语言不适合的问题..

提前致谢

【问题讨论】:

    标签: networking tcp ocaml


    【解决方案1】:

    性能:可能不会。 OCaml 的线程不提供并行执行,它们只是构建程序的一种方式。 OCaml 运行时本身不是线程安全的,因此唯一可能与单个 OCaml 线程并行执行的代码将是接口 C 代码(没有对 OCaml 的回调!)。

    在实现方面,运行时有一个互斥体,在调用阻塞 C 原语时释放,也可以在调用执行重要工作的 C 函数时释放。

    易于实施:它不会改变世界。您将拥有 OCaml 的舒适性和类似 pthread 的库。如果您正在寻找新事物,同时利用您对 OCaml 的了解,我推荐 Jocaml。它与 OCaml 同步和不同步,但最近有一个(重新)重新实现,即使它稍微不同步,它也很有趣,并且是并发程序的全新视角。

    Jocaml 是在 OCaml 之上实现的。由于运行时不是并发的,我几乎可以肯定它使用单独的进程和消息传递。但是对于您提到的应用程序,它应该可以做得很好。

    【讨论】:

    • JoCaml 提供了一个(非常好的)基于消息传递给程序员的并发模型。您的基本 JoCaml 程序在单个 Caml 运行时中运行;在幕后,消息在该运行时的线程之间发送。 JoCaml 还为分布式编程提供了便利:消息可以在甚至不需要在同一台机器上运行的运行时之间透明地发送。如果您使用它,则不会特别利用运行时恰好在同一台机器上运行的特殊情况。
    【解决方案2】:

    OCaml 非常适合编写网络服务器,尽管正如 Pascal 所观察到的,线程化存在局限性。

    不过,幸运的是,线程并不是组织此类程序的唯一方法。 Lwt 库(用于轻量级线程)提供了一种非常易于使用的异步 I/O 抽象(特别是在结合一些语法支持时)。一切实际上都在一个线程中运行,但它全部由异步 I/O 循环驱动(建立在 Unix select 调用之上),并且编程风格让您可以编写看起来像直接代码的代码(避免大部分正常的代码开销在许多其他语言中进行异步 I/O)。例如:

    lwt my_message = read_message socket in
    let repsonse = compute_response my_message in
    send_response socket response
    

    读取和写入都发生在主事件循环中,但您避免了正常的“读取,完成后调用此函数”的手动开销。

    【讨论】:

      【解决方案3】:

      很抱歉,这个问题已经在这里坐了八年,我认为有几个非常糟糕的答案,因为他们都忽略了房间里的大象。

      您说“非常典型,就像每个客户端都有一个线程”,但每个客户端都有一个操作系统线程是非常糟糕的设计。线程是重量级的,创建和销毁需要很长时间,仅线程堆栈就消耗约 1MB。如果每个连接有一个线程,那么 1,000 个同时的客户端连接(这是完全可行的)将为它们的堆栈消耗 1GB 的 RAM,并且您的程序(在任何语言中)的性能将被获取所需的上下文切换量所削弱完成的任何工作。您不想在任何语言中使用该设计,包括 C 和 OCaml。请注意,这个问题在跟踪垃圾收集语言的上下文中特别糟糕,因为 GC 还遍历所有这些线程堆栈,以便在每个 GC 周期之前整理全局根。我是第一个承认这种反模式在现实世界中无处不在但请不要复制它的人!我已经看到金融行业中的“低延迟”服务器是用 C++ 编写的,每个连接使用一个线程,并且仅在 (Windows) 操作系统为这些线程提供服务时,它们就遭受了长达 6 秒的延迟停顿。

      见:http://people.eecs.berkeley.edu/~sangjin/2012/12/21/epoll-vs-kqueue.html

      让我们考虑一个高效的设计,例如操作系统内核的 epoll 或 kqueue 接口,为服务器提供有关传入和传出数据缓冲区的代码信息。单线程服务器可以通过这种设计获得出色的性能。但是,典型的服务器需要为每个客户端执行序列化工作,并且一些核心工作通常在所有客户端连接中以串行方式执行。因此,序列化和反序列化可以并行,但核心服务器操作不能。在这种情况下,OCaml 非常适合除序列化层之外的所有内容,因为它对并行性的支持很差。

      我亲自为各行各业实现了许多服务器,它们的性能要求各不相同。根据我的经验,OCaml 是最好的工具之一,因为它提供了出色的库(易于使用且可靠)和出色的串行性能。我唯一遇到的问题是并行化序列化层,但实际上,我发现 OCaml 围绕 Java 和 .NET 等替代方案运行,即使它们可以并行化。我发现 .NET 的典型延迟约为 100us,OCaml 的典型延迟为 10us。

      另见:http://prl.ccs.neu.edu/blog/2016/05/24/measuring-gc-latencies-in-haskell-ocaml-racket/

      【讨论】:

        【解决方案4】:

        OCaml 非常适用于网络应用程序,只要您可以同时处理相对较少的活动线程(例如不超过 100 个)。您可以将 MLdonkey 视为示例,尽管在客户端空间中,而不是在客户端空间中服务器空间。

        【讨论】:

          【解决方案5】:

          如果您想使用许多抢占式线程,Haskell 将是一个更好的选择。 GHC 可以支持大量线程并且它们在多核系统上并行运行。 OCaml 更喜欢协作多线程和多进程。

          【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-01-31
          • 1970-01-01
          • 2011-03-24
          • 2022-01-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多