Table of Contents
Core differences between the standard library asyncdispatch and Chronos
Chronos was initially forked from the async library in the Nim standard library - it has since grown into its own project with a different API, goals, features and development pace. In particular, we are using the library as a core component of a peer-to-peer application and will continue building other libraries on top of it, such as libp2p.
We welcome that the community ports these changes back to the standard library where it makes sense to do so, but given that we have not finished designing and developing it, we may be breaking the API making it unsuitable for standard library inclusion.
At the time of the fork, the following differences where considered significant - both libraries may have evolved since then:
-
Unified callback type
CallbackFunc
:Current version of asyncdispatch uses many types of callbacks:
proc ()
is used in callSoon() callbacks and Future[T] completion callbacks.proc (fut: Future[T])
is used in Future[T] completion callbacks.proc (fd: AsyncFD, bytesTransferred: Dword, errcode: OSErrorCode)
is used in Windows IO completion callbacks.proc (fd: AsyncFD): bool
is used in Unix IO event callbacks.
Such a large number of different types creates big problems in the storage and processing of callbacks and in interaction between callbacks. Lack of ability to pass custom user data to a callback also creates difficulties and inefficiency with passing custom, user-defined data needed for using closures (one more allocation).
To resolve this issue, we have introduced a unified callback type,
CallbackFunc
:type CallbackFunc* = proc (arg: pointer = nil) {.gcsafe.}
Also, one more type was introduced for the callback storage,
AsyncCallback
:type AsyncCallback* = object function*: CallbackFunc udata*: pointer
-
The order of Future[T] completion callbacks:
Current version of asyncdispatch processes Future[T] completion callbacks in reverse order, but Chronos schedules callbacks in forward order: https://github.com/nim-lang/Nim/issues/7197
-
Changed the behavior of OS descriptor event callbacks:
For some unknown reason, the current version of asyncdispatch uses seq[T] to hold a list of descriptor event listeners. However, in the asynchronous environment, there is no need for a list of event listeners. In Chronos, there is only one place for one READ listener and one place for one WRITE listener.
-
Removed the default timeout value for the poll() procedure, which allows incorrect usage of asyncdispatch and produces 500-ms timeouts in correct usage.
-
Changed the behavior of the scheduler in the poll() procedure, and fixed the following issues:
-
Chronos no longer uses
epochTime()
; instead, it uses the fastest time primitives for a specific OS,fastEpochTime()
. Also, because MacOS supports only a millisecond resolution inkqueue
, sub-millisecond resolution is not needed. For details, see https://github.com/nim-lang/Nim/issues/3909. -
Removed all IO primitives (
recv()
,recvFrom()
,connect()
,accept()
,send()
, andsendTo()
) from the public API, and moved all their functionality into Transports. -
Introduced an
addTimer()
/removeTimer()
callback interface. -
Introduced
removeReader()
foraddReader()
andremoveWriter()
foraddWriter()
. -
Changed the behavior of the
addReader()
,addWriter()
, andaddTimer()
callbacks. Now, only the explicit removal of the callbacks must be supplied viaremoveReader()
,removeWriter()
, andremoveTimer()
. -
Added the support for the cross-platform
sendfile()
operation. -
Removed the expensive
AsyncEvent
and the support for hardware timers andaddProcess
.addProcess
will be implemented as SubprocessTransport, while hardware-basedAsyncEvent
will be renamed toThreadAsyncEvent
. -
Added cheap synchronization primitives:
AsyncLock
,AsyncEvent
, andAsyncQueue[T]
.