这就是我想出的:
var terminated = falsedispatchQueue.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-a Swift snapshot),RunLoop.current().run存在但有错误.下面是一个有效的linux版本,用timer和dispatch_main重新实现.它遇到了相同的延迟问题:
let queue = dispatch_get_main_queue()let timer = dispatch_source_create(disPATCH_SOURCE_TYPE_TIMER,queue)let interval = 0.01let 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()解决方法 在GitHub上快速搜索Open Source Swift Foundation库可以发现CFRunLoop中的支持(可能显然)在不同平台上的实现方式不同.从本质上讲,这意味着RunLoop和libevent就跨平台而言,只是实现同样事物的不同方式.我可以看到libevent可能更适合服务器实现的思想背后的想法,因为CFRunLoop并没有随着特定的目标而成长,但就跨平台而言,它们都在同一棵树上咆哮.
也就是说,RunLoop和libevent使用的底层同步原语本质上是私有的实现细节,更重要的是,平台之间可能不同.从源代码来看,看起来RunLoop在linux上使用epoll,libevent也是如此,但在macOS / iOS /等上,RunLoop将使用Mach端口作为其基本原语,但libevent看起来似乎会使用kqueue.您可以通过足够的努力,创建一个与给定平台的自由源相关联的混合RunLoopSource,但这可能非常脆弱,而且通常是不明智的,原因如下:首先,它将是基于RunLoop的私有实现细节,这些细节不属于公共API,因此可能随时更改,恕不另行通知.其次,假设你没有通过并为swift和libevent支持的每个平台执行此 *** 作,那么你就会破坏它的跨平台性,这是你在第一时间与libevent一起讨论的原因之一.
您可能没有考虑过的另一个选项是在没有RunLoops的情况下单独使用GCD.查看dispatch_main
的文档.在服务器应用程序中,(通常)没有什么特别的“主线程”,因此调度到“主队列”应该足够好(如果需要的话).您可以使用调度“来源”来管理您的连接等.我无法亲自谈论调度源如何扩展到C10K / C100K /等.等级,但在我的经验中,它们看起来非常轻巧,低开销.我也怀疑像这样使用GCD可能是在Swift中编写服务器应用程序的最惯用的方式.作为another answer here的一部分,我写了一个基于GCD的TCP echo服务器的小例子.
如果你被绑定并决定在同一个应用程序中同时使用RunLoop和libevent,那么,正如你所猜测的那样,最好将libevent放在自己独立的线程中,但我认为它并不像你想象的那么复杂.您应该可以自由地从libevent回调中调度dispas_async,并且类似地编组来自GCD托管线程的回复,以便相当容易地使用libevent的多线程机制(即通过锁定运行,或者通过将调用编组为libevent作为事件本身).同样,即使您选择使用libevent的循环结构,使用GCD的第三方库也不应成为问题. GCD管理自己的线程池,无法踩到libevent的主循环等.
您可能还会考虑构建应用程序,使得您使用的并发和连接处理库无关紧要.然后你可以换掉libevent,GCD,CFStreams等(或混合搭配),具体取决于对给定情况或部署最有效的方法.选择并发方法很重要,但理想情况下,如果情况需要,您就不会将自己与自己紧密联系起来.
当你拥有这样的架构时,我通常会喜欢使用最高级别抽象来完成工作的方法,并且只有在特定情况需要时才会降低到较低级别的抽象.在这种情况下,这可能意味着使用CFStreams和RunLoops启动,并切换到“裸”GCD或稍后解放,如果你碰壁并且还确定(通过经验测量)它是传输层而不是应用程序层是限制因素.很少有非平凡的应用程序实际上解决了传输层中的C10K问题;事情往往必须首先在应用层“扩展”,至少对于比基本消息传递更复杂的应用程序.
总结以上是内存溢出为你收集整理的在Swift中使用libevent和GCD(libdispatch)全部内容,希望文章能够帮你解决在Swift中使用libevent和GCD(libdispatch)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)