The nested send-off call doesn't happen on the same thread (it's in a 
future). Seems like that would be the same as if an unrelated thread called 
send-off while the outer send-off was running.

It does seem like a single-thread solution would be better, not creating so 
many futures. Polling seems pretty crude, but I don't see another way of 
doing it with clojure abstractions. Maybe a pure java solution.

On Tuesday, December 2, 2014 3:47:58 AM UTC-8, Gary Verhaegen wrote:
>
> In the general case, side effects within the swap! function are a bad idea 
> because of the optimistic locking. In your first code snippet, if there is 
> any contention on the atom (and maybe in your app you know there is none 
> because it's only ever accesses by the same single thread), you run the 
> risk of having orphaned futures.
>
> As far as I know there should be no such problem with the agent version. 
> I'm not really sure about the nesting of send-off calls though; that might 
> be the source of your stack overflow. I seem to remember that this was not 
> supported up until 1.4 or 1.5; not sure what the current semantics is.
>
> Depending on how many different event types you're watching for (and how 
> many differet actions you need to take), it might be worth having a single 
> thread managing the queue. Somethin along the line of having a single atom 
> containing a priority queue (or a sorted map?) with, for each event type, 
> the last time the event was observed. At some interval, that event thread 
> could check the queue and run the required handlers based on the current 
> time. When an event arrives, it resets the time associated to its type in 
> the queue.
>
> Whether this is better will depend on your usage pattern. I would just 
> like to point out that creating a future has some non trivial overhead as 
> it also creates a thread (at least, the last time I checked, futures where 
> not created out of a limited thread pool).
>
> On Tuesday, 2 December 2014, Erik Price <er...@zensight.co <javascript:>> 
> wrote:
>
>> Coincidentally, we recently wrote code to do something very similar. The 
>> following function will invoke f after period milliseconds, unless a 
>> value is sent on events-ch, in which case the timeout is reset (and 
>> starts counting down again):
>>
>> (defn invoke-after-uninterrupted-delay
>>   ([period events-ch f]
>>     (invoke-after-uninterrupted-delay period events-ch f []))
>>   ([period events-ch f & args]
>>     (async/go-loop []
>>       (let [[_ p] (async/alts! [(async/timeout period) events-ch])]
>>         (if (= p events-ch)
>>           (recur)
>>           (apply f args))))))
>>
>> e
>> ​
>>
>> On Mon, Dec 1, 2014 at 6:50 PM, Brian Craft <craft.br...@gmail.com> 
>> wrote:
>>
>>> That version has the unfortunate behavior that (func) can be interrupted 
>>> if (event) is called while it is running. Here's another version using an 
>>> agent:
>>>
>>> (defn queue-with-delay2 [period func]
>>>   (let [q (agent nil)]
>>>     (fn []
>>>       (send-off q (fn [t]
>>>                     (when t
>>>                       (future-cancel t))
>>>                     (future (Thread/sleep period) (send-off q (fn [_] 
>>> (func) nil))))))))
>>>
>>> Running with a sleep to see that (func) is not canceled by subsequence 
>>> (event) calls:
>>>
>>> (def event (queue-with-delay2 2000 #(do (println "running") 
>>> (Thread/sleep 2000) (println "ending"))))
>>>
>>> Oddly, if calling (event) between "running" and "ending" messages, the 
>>> repl will stack-overflow on the return value. No idea what that's about. 
>>> But, running like this is fine:
>>>
>>> (do (event) nil)
>>>
>>>
>>>
>>>
>>>
>>> On Monday, December 1, 2014 1:37:56 PM UTC-8, Brian Craft wrote:
>>>>
>>>> I have need to perform an action when a series of events is quiet for 
>>>> some period. That is, if one event arrives an action is queued to execute 
>>>> after some timeout. If a second event arrives the timeout is reset, and 
>>>> so-forth.
>>>>
>>>> The following code seems to work, however I'm wondering if calling 
>>>> 'future' from 'swap!' is a bad idea (side effecting), and if there's a 
>>>> better way.
>>>>
>>>> (defn queue-with-delay [period func]
>>>>   (let [f (atom nil)]
>>>>     (fn []
>>>>       (when @f
>>>>         (future-cancel @f))
>>>>       (swap! f (fn [_] (future (Thread/sleep period) (func)))))))
>>>>
>>>>
>>>> Use like
>>>>
>>>> (def event (queue-with-delay 2000 #(println "running")))
>>>> (event)
>>>> (event)
>>>> (event)  ; pause 2 sec
>>>> "running"
>>>>
>>>>
>>>>
>>>>  -- 
>>> 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.
>>> For more options, visit https://groups.google.com/d/optout.
>>>
>>
>>  -- 
>> 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.
>> For more options, visit https://groups.google.com/d/optout.
>>
>

-- 
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.
For more options, visit https://groups.google.com/d/optout.

Reply via email to