Writing a simple web server, for example, is trivial.
Tk accesses the C-based event API to turn things like button clicks into events. Python (and Ruby?) ships with Tcl in order to make use of Tk.
There's a thread extension that makes it easy to spawn separate threads which can inject events into the event loop, making hybrid event/thread programming simple.
The best part for me, however, was that in Tcl you can have multiple interpreters in the same process, each in its own native thread if you want. No GIL, no need to pickle/unpickle to talk the other interpreter. Had Python adopted this model, using multiple cores would have been so much nicer.
That said, the mantle has passed on to Lua, but I still harbor a soft corner for Tcl.
I know tcl and node are runtimes - but what do you get extra in their event loops compared to standard event loops that Linux offers?
On systems that implement them, Tcl can use select, epoll, kqueue for its event notification implementation, as well as pthread_cond_broadcast for threads (if built with thread support).
take a look at:
generic/tclNotify.c - https://core.tcl.tk/tcl/artifact/8804164706c8f2cb
unix/tclEpollNotfy.c - https://core.tcl.tk/tcl/artifact/892b68fa5a7c4c87
Tcl is a command-based, imperative language. Tcl has threads.
They work mostly like you'd expect: shared variables, mutexes, condition variables.
Threads can send script code to another thread using thread::send -async and thread::broadcast:
https://www.tcl.tk/man/tcl/ThreadCmd/thread.htm#M17
Tcl does let you write DSL-like libraries, and because you can easily hotswap code (being homoiconic like Lisp), it also works well for distributing your execution environment across several network nodes.
But the language itself isn't "innately async". The thread model isn't based on message passing, CSP, Pi calculus, or any other strong idea. I always thought of it as "string-focused Lisp".