<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Hi Johannes,<div class=""><br class=""></div><div class="">By&nbsp;synchronous/asynchronous I am referring to the natural of the API, something like</div><div class=""><br class=""></div><div class="">```sync</div><div class="">func read(fd:, to buffer:) throws&nbsp;</div><div class="">```</div><div class=""><div class="">```async</div><div class="">func read(fd:, handiler: (buffer)-&gt;R) throws -&gt; R&nbsp;</div><div class="">```</div></div><div class=""><div class=""><blockquote type="cite" class=""><div class=""><div class="">Not really, what you do when you use kqueue/(e)poll/select is that only said calls are blocking and you set your file descriptors to non-blocking.<br class=""></div></div></blockquote><div class=""><br class=""></div>Despite kqueue is a blocking, it really only blocks when there’s nothing to do. So semantic-wise, the thread will never block as long as there’s work to do.</div><div class=""><br class=""><blockquote type="cite" class=""><div class=""><div class="">if you use kqueue/(e)poll/select you get inversion of control, ie. you block only one (or a few) threads in kqueue/epoll/select and then invoke code to handle the event (which can be 'file descriptor XYZ can be read/written').<br class=""><br class="">So the echo server becomes more like this (this is extreme pseudo code and ignores most of the real challenges)<br class=""><br class="">func echoServer(socket: Socket) {<br class=""> &nbsp;&nbsp;&nbsp;socket.whenReadable { bytes in<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;socket.whenWritable {<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;socket.write(bytes)<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br class=""> &nbsp;&nbsp;&nbsp;}<br class="">}<br class=""><br class=""></div></div></blockquote><div class=""><br class=""></div>That’s not quite true, the gold of kqueue and event notification apis is that you can pick when you want to read from the socket (in fact you don’t necessarily have to set then non-block), which is in fact more like coroutine.</div><div class=""><br class=""></div><div class="">This also say that there’s read available, they know exactly which thread will execute on and the sequence of execution, so no external mechanism required to synchronize resources.</div><div class=""><br class=""></div><div class="">while im_feeling_lucky {</div><div class="">&nbsp; if (feeling_good) {</div><div class="">&nbsp; &nbsp; kevent(…)</div><div class="">&nbsp; &nbsp; &nbsp; for ev in events_i_can_do {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; if (happy(ev)) {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; read(ev,….)</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; &nbsp; }</div></div><div class=""><div class="">&nbsp; &nbsp; }</div><div class="">}</div><div class=""><br class=""></div><div class="">In fact in kqueue you can even temporarily disable events, or simply not call kevent when the server is under pressure.&nbsp;</div><div class=""><br class=""></div><div class="">With a Synchronous IO API, the user have 100% control on when read/write occur, on which thread it occur, how many partial bytes to read and synchronize shared resources without lock etc.</div><div class=""><br class=""></div><div class="">If we only provide a asynchronous API, some existing server-side framework, say Perfect, very hard to integrate with the official one.</div><div class=""><br class=""><blockquote type="cite" class=""><div class=""><div class="">If you want a more realistic example check out DispatchSources and DispatchIO from Dispatch. The important bit is that if you use these eventing solutions, you'll get inversion of control and that's commonly referred to as an asynchronous API as you can't do anything in the current thread but have to do it when the eventing library tells you to. Cf. also the HTTP API that I was initially proposing and a HTTP echo server for that:<br class=""></div></div></blockquote><div class=""><br class=""></div><div class="">There’s timeout option on both api, and usually these api only block when there’s nothing to do.</div><div class="">You don’t have to handle those event if you don’t want to as well, you can always not to set&nbsp;EPOLLET and not handle the event, which is totally fine, and handle it next time you call kevent.</div><br class=""><blockquote type="cite" class=""><div class=""><div class="">--- SNIP ---<br class="">serve { (req, res) in<br class=""> &nbsp;if req.target == "/echo" {<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;guard req.httpVersion == (1, 1) else {<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/* HTTP/1.0 doesn't support chunked encoding */<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.writeResponse(HTTPResponse(version: req.version,<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status: .httpVersionNotSupported,<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;transferEncoding: .identity(contentLength: 0)))<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.done()<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return .discardBody<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.writeResponse(HTTPResponse(version: req.version,<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status: .ok,<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;transferEncoding: .chunked,<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;headers: SomeConcreteHTTPHeaders([("X-foo": "bar")])))<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return .processBody { (chunk, stop) in<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch chunk {<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case .chunk(let data, let finishedProcessing):<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.writeBody(data: data) { _ in<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;finishedProcessing()<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case .end:<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.done()<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default:<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stop = true /* don't call us anymore */<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.abort()<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br class=""> &nbsp;} else { ... }<br class="">}<br class="">--- SNAP ---<br class=""><br class="">You'll see that we return a closure to process the individual chunks of an HTTP body (`return .processBody { ... }`) and register a write of the response when that closure got invoked by the eventing library.<br class=""><br class=""></div></div></blockquote><div class=""><br class=""></div><div class="">Parsing is another story, tho the synchronous api can be something like</div><div class=""><br class=""></div><div class="">parser.processBody = &nbsp;{ (chunk, stop) in</div><div class="">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; switch chunk {</div><div class="">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case .chunk(let data, let finishedProcessing):</div><div class="">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; res.writeBody(data: data) { _ in</div><div class="">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; finishedProcessing()</div><div class="">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div class="">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case .end:</div><div class="">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; res.done()</div><div class="">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; default:</div><div class="">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; stop = true /* don't call us anymore */</div><div class="">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; res.abort()</div><div class="">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; }</div><div class="">&nbsp;&nbsp; &nbsp; }</div><div class=""><br class=""></div><div class="">typealias Done = Bool</div><div class="">extension Parser {</div><div class="">func feed(data: AnyCollection&lt;UnsafeBufferPointer&gt;) -&gt; Done</div><div class="">}</div><div class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div class="">can you expand on this? What you get with kqueue/epoll is an asynchronous API so I reckon there's just some misunderstanding in terminology.<br class=""></div></div></blockquote><br class=""></div><div class="">As mentioned as above, one can choose which thread, when to read, where is the buffer and how to synchronous resources.</div><div class=""><br class=""></div><div class="">Assuming I’m somehow writing a server that somehow have some strange requirement,</div><div class="">since the asynchronous approach is that the event library calling preset handler whenever <b class="">payload arrives, </b>which with a mix with kqueue I can choose not to handle any (by simply not to call kevent) and call (kevent) from my code when <b class="">I’m ready.</b></div><div class=""><b class=""><br class=""></b></div><div class="">It also let me handle the req one by one without locking resources for synchronization and I can even allocate a single buffer in the stack for all connections.&nbsp;</div><div class=""><br class=""></div><div class="">None of these can easily done if only asynchronous API is provided. (People can always fall back to C API, but it doesn’t help server side swift much).</div></div><div class=""><br class=""></div><div class="">Cheers,</div><div class="">Michael.</div><div class=""><br class=""></div><div class=""><br class=""></div></div></body></html>