metosin / sieppari

Small, fast, and complete interceptor library for Clojure/Script
Eclipse Public License 2.0
207 stars 21 forks source link

For discussion. Another async context protocol #40

Closed dspiteself closed 4 years ago

dspiteself commented 4 years ago

This is a demonstration not to merge. I did a refactor of the AsyncContext protocol. dereffables and deferred run between 1/3-1/5 the time in perf_testing.clj core.async async benchmark got a more modest 34% reduction in runtime.

The previous shape of the AsyncContext protocol required much communication with the thread that started the pipeline. The goal of this branch was to explore letting the main thread go sooner and minimizing context switches as we pass the computation from one async context to another.

I took care to ensure that I was not blocking the thread when I could help it, but there could still be issues with users blocking inside interceptor functions.

I left 4 errors and 18 failures that are mostly caused by differences if implementation function boundaries. I got just enough tests working to have a bit of confidence of the outcome. The handler interceptor caused most of the ugliness of branch.

The previous shape required much communication with the thread that started the pipeline.

I made 3 main changes:

  1. I brought back a go-async handler like pedestal had. This allowed me to free the thread that started the pipeline faster. I used a clojure.core/promise to emulate the blocking on the calls that required it.
  2. I combined the catch and continue into continue.In order to do this I had to pass in the previous context so the exceptions could be assoced on.
  3. I used more primitive functions on core.async and manifold. In manifold I made a fastpath if the deferred was realized. This could be generalized to other AsyncContext.

I think the work in 3 could be adapted without such significant changes.