Re: Why is `binding-conveyor-fn` private?

2020-08-23 Thread jum...@gmail.com
I'm just wondering what's the point of binding-conveyor-fn and why is the 
implementation so different from `bound-fn` et al.
It seems that the core functions use only binding-conveyor-fn.

On Friday, 21 August 2020 at 20:32:14 UTC+2 Sean Corfield wrote:

> Isn't that what bound-fn and bound-fn* are for?
>
> On Fri, Aug 21, 2020 at 11:21 AM Dimitrios Jim Piliouras <
> jimpi...@gmail.com> wrote:
>
>> Hi folks,
>>
>> I don’t get this…
>>
>> Why would such a neat/important utility private? Every time I 
>> submit/schedule a function to some Executor manually (not via `future`
>>  or `agent`), I need to remember to wrap it with `binding-conveyor-fn` 
>> (otherwise dynamic bindings won’t get propagated), and every time I have to 
>> copy/paste it into whatever project I’m working in. 
>>
>> Shouldn’t it, not only be public, but also come with a doc-string that 
>> strongly encourages its use  when manually submitting functions to 
>> Executors? Am I missing something?
>>
>> Many thanks in advance... 
>>
>> Kind regards,
>> Dimitrios
>>
>> -- 
>> You received this message because you are subscribed to the Google
>> Groups "Clojure" group.
>> To post to this group, send email to clo...@googlegroups.com
>> Note that posts from new members are moderated - please be patient with 
>> your first post.
>> To unsubscribe from this group, send email to
>> clojure+u...@googlegroups.com
>> For more options, visit this group at
>> http://groups.google.com/group/clojure?hl=en
>> --- 
>> You received this message because you are subscribed to the Google Groups 
>> "Clojure" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to clojure+u...@googlegroups.com.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/clojure/A6C14F3B-D725-4B11-9A8F-4C008DC1BB3D%40gmail.com
>> .
>>
>
>
> -- 
> Sean A Corfield -- (904) 302-SEAN
> An Architect's View -- https://corfield.org/
> World Singles Networks, LLC. -- https://worldsinglesnetworks.com/
>
> "Perfection is the enemy of the good."
> -- Gustave Flaubert, French realist novelist (1821-1880)
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/clojure/89be86cf-b2c1-4fab-a9fa-80eae2142been%40googlegroups.com.


Re: Socket servers, threads, and redirecting error output.

2021-01-06 Thread jum...@gmail.com
Thanks Sean, the stuff with file/line and thread name was helpful!
I updated my own logging-future macro(s) - here's an interesting version 
(logging-future+) that logs the client stacktrace at the time when it 
called future. 
I often find that much more useful that the stacktrace inside the thread 
itself, especially when using things like 
Hystrix: 
https://github.com/jumarko/clojure-experiments/blob/master/src/clojure_experiments/concurrency.clj#L31-L50
```
(defn logging-future+* [file line body]
  `(let [client-stack-trace# (Exception. "Client stack trace")]
 (future
   (try ~@body
(catch Throwable e#
  (log/error e# "Unhandled exception at:"
   ~file "line:" ~line
   "on thread:"
   (.getName (Thread/currentThread)))
  (log/error client-stack-trace# "client stack trace:"))
```


On Tuesday, 5 January 2021 at 17:51:42 UTC+1 Austin Haas wrote:

> Thank you, Sean. That is an excellent example.
>
> -austin
>
> On Sunday, January 3, 2021 at 12:48:55 PM UTC-8 Sean Corfield wrote:
>
>> Austin,
>>
>> You might find a macro like this helpful -- just use it directly instead 
>> of future. You can replace println with whatever sort of logging you want.
>>
>> (defmacro logged-future
>> "Given a body, execute it in a try/catch and log any errors."
>> [& body]
>> (let [line (:line (meta &form))
>> file *file*]
>> `(future
>> (try
>> ~@body
>> (catch Throwable t#
>> (println t# "Unhandled exception at:"
>> ~file "line:" ~line
>> "on thread:"
>> (.getName (Thread/currentThread
>>
>>
>> On Sat, Jan 2, 2021 at 5:59 PM Austin Haas  wrote:
>>
>>> Ah, thanks for pointing that out. I must've overlooked your example, 
>>> because I'd already written off futures.
>>>
>>> It seems like what you are suggesting, catch and print, might be about 
>>> as good as I could hope for. If I don't want to block the main thread, then 
>>> I don't see what else I could possibly do but print the exception. I guess 
>>> I could store it somewhere, but in any case, I'd use this same pattern.
>>>
>>> Thanks, Justin.
>>> On Saturday, January 2, 2021 at 1:44:55 PM UTC-8 noise...@gmail.com 
>>> wrote:
>>>
 to be clear, in my second example you see the error from the future 
 without using deref

 good luck finding your solution

 On Sat, Jan 2, 2021 at 12:50 PM Austin Haas  
 wrote:

> Thank you very much for the explanation, Justin.
>
> I don't see how I can use futures, though, without blocking on the 
> main thread (to get the exception when it occurs). I'm spawning a 
> long-running process that never returns a value.
> On Saturday, January 2, 2021 at 12:43:14 AM UTC-8 noise...@gmail.com 
> wrote:
>
>> By the time the exception is caught, you are already outside the 
>> context of the Thread which the repl client is interacting with. The 
>> default exception handler has no information tying the executing thread 
>> to 
>> the repl process (not to mention the dynamic variables clojure is using 
>> to 
>> associate output from code your client runs with that socket connection).
>>
>> You probably don't want to rebind the root exception handler to show 
>> *all* exceptions to your client socket. Which means that you need to set 
>> up 
>> some soft of infrastructure connecting the information about the failed 
>> function to the socket you are listening to.
>>
>> I find "future" very convenient for this, it uses a pool which will 
>>  perform better than creating Threads ad-hoc, and will capture 
>> Exceptions 
>> and re-throw when you deref (of course, it's up to you to ensure you 
>> deref, 
>> or use try/catch and otherwise forward the failure information via the 
>> catch block). Also, it conveys dynamic bindings for things like 
>> clojure.core/*out* and clojure.core/*err* that java classes don't know 
>> about.
>>
>> (ins)user=> (def fut (future (throw (Exception. "oops"
>> #'user/fut
>> (ins)user=> @fut ; waits until deref to raise the error
>> Execution error at user/fn (REPL:11).
>> oops
>> (ins)user=> (def fut2 (future (try (throw (Exception. "oops")) (catch 
>> Exception e (println "wat\n" e) ; prints instead of raising
>> #'user/fut2
>> user=> wat
>>  #error {
>>  :cause oops
>>  :via
>>  [{:type java.lang.Exception
>>:message oops
>>:at [user$fn__165 invokeStatic NO_SOURCE_FILE 13]}]
>>  :trace
>>  [[user$fn__165 invokeStatic NO_SOURCE_FILE 13]
>>   [user$fn__165 invoke NO_SOURCE_FILE 13]
>>   [clojure.core$binding_conveyor_fn$fn__5754 invoke core.clj 2030]
>>   [clojure.lang.AFn call AFn.java 18]
>>   [java.util.concurrent.FutureTask run FutureTask.java 264]
>>   [java.util.concurrent.ThreadPoolExecutor runWorker 
>> ThreadPoolExecutor.java 1128]
>>

Re: function call speed...

2024-12-05 Thread jum...@gmail.com
A discussion about this on Clojurians 
slack: https://clojurians.slack.com/archives/C03L9H1FBM4/p1728361006109229
A couple of highlights: 
- apply is very slow and allocating. Desctucturing is suboptimal, 
especially for lists.
- If you look at the apply method's implementation 
, 
you see why it is much slower than regular fn call. It walks the seq to get 
each of the fn args, then calls invoke. It's a lot of overhead.

On Saturday, 5 October 2024 at 17:59:32 UTC+2 Jules wrote:

> I was just checking to see how much overhead I might pay using apply 
> rather than destructuring a collection of args so I could call a function 
> directly on them, when I found something I thought interesting:
>
> TLDR:
>
> - apply is really slow - 2 orders of magnitude slower than a direct call
> - apply on an array, which I thought would be a direct way to the java 
> varargs api is really slow
> - destructuring a list is two orders of magnitude slower than a vector
> - it is an order of magnitude faster to destructure a vector and may a 
> direct call, than to use apply
> - etc
>
> openjdk full version "21.0.4+7"
> clojure 1.12.0
> AMD Ryzen 9 5950X 16-Core Processor
>
> If I've made any silly mistakes, please point them out and I'll run these 
> benchmarks again.
>
> If I am correct then there should be a lot of room to speed up apply and 
> destructuring of lists ?
>
> Interested in peoples thoughts...
>
>
> Jules
>
>
> m3.repl> ;; let's have function that takes 4 args
> m3.repl> (defn foo [a b c d])
> #'m3.repl/foo
> m3.repl> ;; let's try some direct calls
> m3.repl> (time (dotimes [_ 1] (foo 1 2 3 4)))
> "Elapsed time: 65.149019 msecs"
> nil
> m3.repl> (time (dotimes [_ 1] (foo 1 2 3 4)))
> "Elapsed time: 49.920188 msecs"
> nil
> m3.repl> (time (dotimes [_ 1] (foo 1 2 3 4)))
> "Elapsed time: 48.02132 msecs"
> nil
> m3.repl> ;; now lets try with a variety of collections via apply
> m3.repl> (def vargs [1 2 3 4])
> #'m3.repl/vargs
> m3.repl> (def largs (list 1 2 3 4))
> #'m3.repl/largs
> m3.repl> (def aargs (into-array Object [1 2 3 4]))
> #'m3.repl/aargs
> m3.repl> ;; a vector
> m3.repl> (time (dotimes [_ 1] (apply foo vargs)))
> "Elapsed time: 7166.218804 msecs"
> nil
> m3.repl> (time (dotimes [_ 1] (apply foo vargs)))
> "Elapsed time: 7167.766347 msecs"
> nil
> m3.repl> (time (dotimes [_ 1] (apply foo vargs)))
> "Elapsed time: 7154.58141 msecs"
> nil
> m3.repl> ;; a list
> m3.repl> (time (dotimes [_ 1] (apply foo largs)))
> "Elapsed time: 5657.564262 msecs"
> nil
> m3.repl> (time (dotimes [_ 1] (apply foo largs)))
> "Elapsed time: 5597.083287 msecs"
> nil
> m3.repl> (time (dotimes [_ 1] (apply foo largs)))
> "Elapsed time: 5638.361902 msecs"
> nil
> m3.repl> ;; and an array
> m3.repl> (time (dotimes [_ 1] (apply foo aargs)))
> "Elapsed time: 7954.757485 msecs"
> nil
> m3.repl> (time (dotimes [_ 1] (apply foo aargs)))
> "Elapsed time: 8125.750746 msecs"
> nil
> m3.repl> (time (dotimes [_ 1] (apply foo aargs)))
> "Elapsed time: 8151.5701 msecs"
> nil
> m3.repl> ;; is it faster to destructure first ?
> m3.repl> ;; a vector
> m3.repl> (time (dotimes [_ 1] (let [[a b c d] vargs] (foo a b c 
> d
> "Elapsed time: 904.68628 msecs"
> nil
> m3.repl> (time (dotimes [_ 1] (let [[a b c d] vargs] (foo a b c 
> d
> "Elapsed time: 902.818246 msecs"
> nil
> m3.repl> (time (dotimes [_ 1] (let [[a b c d] vargs] (foo a b c 
> d
> "Elapsed time: 905.498641 msecs"
> nil
> m3.repl> ;; a list
> m3.repl> (time (dotimes [_ 1] (let [[a b c d] largs] (foo a b c 
> d
> "Elapsed time: 30043.489179 msecs"
> nil
> m3.repl> (time (dotimes [_ 1] (let [[a b c d] largs] (foo a b c 
> d
> "Elapsed time: 30159.705918 msecs"
> nil
> m3.repl> (time (dotimes [_ 1] (let [[a b c d] largs] (foo a b c 
> d
> "Elapsed time: 30289.946966 msecs"
> nil
> m3.repl> ;; an array
> m3.repl> (time (dotimes [_ 1] (let [[a b c d] aargs] (foo a b c 
> d
> "Elapsed time: 14231.86232 msecs"
> nil
> m3.repl> (time (dotimes [_ 1] (let [[a b c d] aargs] (foo a b c 
> d
> "Elapsed time: 14081.057031 msecs"
> nil
> m3.repl> (time (dotimes [_ 1] (let [[a b c d] aargs] (foo a b c 
> d
> "Elapsed time: 14924.808985 msecs"
> nil
> m3.repl> ;; hmm... maybe destructuring the vector is taking a shortcut and 
> not building a new collection whereas the others are
> m3.repl> (time (dotimes [_ 1] (let [[a b c d e] vargs] (foo a b c 
> d
> "Elapsed time: 1158.761312 msecs"
> nil
> m3.repl> (time (dotimes [_ 1] (let [[a b c d e] vargs] (foo a b c 
> d
> "Elapsed time: 570.542383 msecs"
> nil
> m3.repl> (time (dotimes [_ 1] (let [[a b c d e] vargs] (foo a b c 
> d
> "Elapsed time: 588.179669 msecs"
> nil
> m3.repl> (time (dotimes [_ 1] (let [[a b c d e] vargs] (foo a b c 
>