在Swift中结合使用libevent和GCD(libdispatch)

兹梅

我正在Swift 3中创建一个服务器端应用程序。我选择libevent来实现网络代码,因为它是跨平台的,并且不会遭受C10k问题的困扰。Libevent实现了它自己的事件循环,但是我也想保持CFRunLoop和GCD(DispatchQueue.main.afteretc)的功能,所以我需要以某种方式粘合它们。

这是我想出的:

var terminated = false

DispatchQueue.main.after(when: DispatchTime.now() + 3) {
    print("Dispatch works!")
    terminated = true
}

while !terminated {
    switch event_base_loop(eventBase, EVLOOP_NONBLOCK) { // libevent
    case 1:
        break // No events were processed
    case 0:
        print("DEBUG: Libevent processed one or more events")
    default: // -1
        print("Unhandled error in network backend")
        exit(1)
    }
    RunLoop.current().run(mode: RunLoopMode.defaultRunLoopMode,
                          before: Date(timeIntervalSinceNow: 0.01))
}

此方法有效,但是引入了0.01秒的延迟。当RunLoop处于睡眠状态时,libevent将无法处理事件。降低此超时时间可在应用程序空闲时显着增加CPU使用率。

我也在考虑仅使用libevent,但是项目中的第三方库可以在内部使用dispatch_async,因此这可能会出现问题。

在另一个线程中运行libevent的循环会使同步更加复杂,这是解决此延迟问题的唯一方法吗?

LINUX更新。上面的代码在Linux上不起作用(2016-07-25-Swift快照),RunLoop.current().run存在错误。以下是使用计时器和重新实现的可工作的Linux版本dispatch_main它遭受相同的延迟问题:

let queue = dispatch_get_main_queue()
let timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue)
let interval = 0.01
let block: () -> () = {
    guard !terminated else {
        print("Quitting")
        exit(0)
    }
    switch server.loop() {
    case 1: break // Just idling
    case 0: break //print("Libevent: processed event(s)")
    default: // -1
        print("Unhandled error in network backend")
        exit(1)
    }
}
block()
let fireTime = dispatch_time(DISPATCH_TIME_NOW, Int64(interval * Double(NSEC_PER_SEC)))
dispatch_source_set_timer(timer, fireTime, UInt64(interval * Double(NSEC_PER_SEC)), UInt64(NSEC_PER_SEC) / 10)
dispatch_source_set_event_handler(timer, block)
dispatch_resume(timer)
dispatch_main()
ipccc

快速搜索GitHub上的Open Source Swift Foundation库显示,CFRunLoop(也许很明显)在不同平台上实现的支持有所不同。从本质上讲,就跨平台性而言,这意味着RunLooplibevent是实现同一件事的不同方法。我看到的想法背后的想法libevent可能更适合服务器实现,因为它CFRunLoop并没有达到特定的目标,但是就跨平台而言,它们都在同一棵树上。

这就是说,所使用的底层同步原语RunLooplibevent本质上是私人的实施细则,或许更重要的是,平台之间的不同从源头上看,就像在Linux上RunLoop使用epoll一样libevent,但在macOS / iOS / etc等上,RunLoop它将使用Mach端口作为其基本原语,但libevent看起来却要使用kqueue您可能经过足够的努力就能制作一个RunLoopSource与给libevent定平台绑定的混合对象,但是由于以下几个原因,这可能非常脆弱,并且通常是不明智的:的私人执行细节RunLoop并非公共API的一部分,因此随时可能更改,恕不另行通知。其次,假设您没有针对Swift和所支持的每个平台进行操作libevent,那么您将破坏它的跨平台性,这首先就是您陈述的原因之一libevent

您可能没有考虑过的另一种选择是不使用GCD本身RunLoops查看有关的文档dispatch_main在服务器应用程序中,(通常)“主线程”没有什么特别的,因此分派到“主队列”应该足够好(如果需要的话)。您可以使用调度“源”来管理您的连接等。我个人不能说调度源如何扩展到C10K / C100K / etc。级别,但以我的经验来看,它们似乎非常轻巧且开销低。我还怀疑这样使用GCD可能是在Swift中编写服务器应用程序的最惯用的方式。我在这里写了一个基于GCD的TCP回显服务器的小示例,作为此处另一个答案的一部分

如果你是约束,并决定同时使用RunLoop,并libevent在同一个应用程序,它会如你猜到了,最好给libevent它自己独立的线程,但我不认为这是因为像你想象的复杂。您应该能够dispatch_asynclibevent回调自由,并从GCD同样元帅回复管理线程libevent使用libevent的多线程机制相当容易地(即,或者通过锁定上运行,或通过编组您的通话将libevent作为事件本身。)同样,第三即使您选择使用libevent的循环结构,使用GCD的第三方库也不应该成为问题。GCD管理自己的线程池,无法踩libevent主循环等。

您可能还会考虑对应用程序进行架构设计,以至于使用哪种并发和连接处理库都没有关系。然后,您可以换出libevent,GCD,CFStreams等(或混合搭配),这取决于在给定情况或部署下最有效的方法。选择并发方法很重要,但是理想情况下,您不会将自己与之紧密地联系在一起,以至于在情况需要时您无法切换。

当您拥有这样的体系结构时,我通常会喜欢使用可以完成工作的最高级别抽象的方法,并且仅在特定情况需要时才使用较低级别的抽象。在这种情况下,这可能意味着使用CFStreamsRunLoops启动,然后切换到“裸” GCD或libevent更高版本,如果您碰壁,并且还确定(通过经验测量)是传输层而不是应用层限制因素。实际上,很少有平凡的应用程序能够解决传输层中的C10K问题。事情往往必须首先在应用程序层“扩展”,至少对于比基本消息传递更复杂的应用程序而言。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

在Swift中结合使用libevent和GCD(libdispatch)

来自分类Dev

为Android编译libDispatch(GCD)

来自分类Dev

使用GCD同步Swift 3中的属性

来自分类Dev

在Swift中结合CGBitmapInfo和CGImageAlphaInfo

来自分类Dev

结合使用NSMutableArray和[Swift Array]

来自分类Dev

结合使用imagePickerController和Swift 2

来自分类Dev

使用Ansible在Linux上安装Swift 3 + libdispatch

来自分类Dev

在熊猫中结合使用遮罩和索引

来自分类Dev

将Gmail API与Xcode 7和Swift结合使用

来自分类Dev

在Swift中创建GCD队列?

来自分类Dev

在Swift CLI中使用GCD

来自分类Dev

Coq中的GCD和mod

来自分类Dev

结合使用.not()和.empty()

来自分类Dev

结合使用^和变量

来自分类Dev

AND和OR结合NSPredicate。iOS Swift

来自分类Dev

AND和OR结合NSPredicate。iOS Swift

来自分类Dev

结合减少和过滤Swift

来自分类Dev

使用Swifty在字典中结合JSON和String

来自分类Dev

如何在Django模板中结合使用QuerySet和Dictionary?

来自分类Dev

在Python中结合使用max,xrange和lambda函数

来自分类Dev

在AngularJS中结合使用transclude和指令继承

来自分类Dev

我可以在单个联接中结合使用和启用吗?

来自分类Dev

结合使用setTimeout和Canvas从数组中打印文本

来自分类Dev

在shell脚本中,如何结合使用Rscript和Unix命令?

来自分类Dev

在Chrome插件中结合使用Python和Javascript

来自分类Dev

可以在psql中结合使用-c和-v吗?

来自分类Dev

在TSQL中结合使用Pivot函数和Sum函数

来自分类Dev

结合使用HBase和HDFS会导致makeDirOnFileSystem中的异常

来自分类Dev

在WHERE SQL中结合使用CONCAT和RTRIM