Fork me on GitHub
#pathom
<
2021-01-15
>
wilkerlucio19:01:37

hello everybody, I want to share with you some findings I just did. I'm working on the async support for Pathom 3, and this time I decided to compare two different implementations, one based in core.async and one based in promesa. I made the two implementations, and ran some benchmarks, here are the results: https://gist.github.com/wilkerlucio/a1cda78802c8a5f9cab92cb7c52fa69b

🚀 9
💯 3
wilkerlucio19:01:54

when I tried the core.async implementation I was a bit sad with the performance results, but than seeing those with Promesa made me really excited! the overhead using Promesa is quite close to the serial processing, which is a lot faster than every version of Pathom before that! and I would love to hear if have any opinions about this direction 🙏

imre21:01:57

Impressive! Can it be made pluggable?

wilkerlucio21:01:24

you can convert anything to a promise-like from promise, as long as you have some way to trigger the callbacks (for resolving or rejecting), so you could wrap a channel to make it do it. is this what you were asking about?

dehli22:01:25

it would be great if there could be one spot that we could do the channel -> promise conversion so that we could have our resolvers just return channels if we wanted

dehli22:01:02

and then we can appropriately handle promise rejections in one spot as well since traditionally core async channels don’t really have a notion of “rejecting”

dehli23:01:41

Something similar to how sieppari works would be awesome where by default it only supports promesa but you can bring in another namespace to extend what async libraries are supported (https://github.com/metosin/sieppari#external-async-libraries)

wilkerlucio16:01:55

I did some play here, and I checked its possible to also implement a promesa protocol to make other async things fulfill it, here is an example using core.async via said extension:

(extend-type cljs.core.async.impl.channels/ManyToManyChannel
  promesa.protocols/IPromiseFactory
  (-promise [this]
    (p/create
      (fn [resolve reject]
        (go
          (let [v (<! this)]
            (if (error? v)
              (reject v)
              (resolve v))))))))

(comment
  (let [start (system-time)]
    (-> (p.a.eql/process (pci/register
                           (pco/resolver 'foo {::pco/output [:foo-async]}
                             (fn [_ _] (go {:foo-async "the-value"}))))
          [:foo-async])

        (p/handle (fn [result error]
                    (println "RES" result error))))))

wilkerlucio16:01:38

I probably wont provide this in the library to avoid having the dep on core.async at all, but it can be a separated library, or a documentation page with the snippet

wilkerlucio16:01:56

what you think?

mpenet17:01:09

Good approach. I really like core.async myself but having completablefutures is a good default, especially on the jvm. And it's easy to plug one into the others (you can make completablefuture impl for core. async readport/writeport that follows promise-chan impl, then overhead is really low I guess)

mpenet17:01:28

I wouldn't bake in interceptor usage tho, this is more opinionated, there's no standard and there are multiple good impl. in clojure with subtle differences.

👍 3
dehli13:01:15

I think that’s a great solution! like you said it could be a separate library if there’s enough demand for it but it’s also a pretty small change that just mentioning it in the README should be enough

👍 3
nivekuil22:01:44

I like promesa too. I think it is really close to bare CompletableFuture overhead

royalaid22:01:30

Is it possible to provide channel coercion in pathom3?

royalaid22:01:39

then you could possibly get the best of both worlds

royalaid22:01:15

compatibility with core.async and performance of promesa

royalaid22:01:26

it might also be worth looking at kitchen-async(https://github.com/mhuebert/kitchen-async)