Nilling for GC


#1

Hi, I’ve read that
http://whytheluckystiff.net/articles/theFullyUpturnedBin.html.
I have a background script that runs continuously and threads some tasks
on demand. I keep track of the launched tasks but, by keeping those
tracks, I certainly prevent tasks classes instances and threads
instances to be discarded by the garbage collector.

Data are stored like that :

@workers[:one_category] = []
@workers[:one_category] << {:started_at => Time.now, :thread => th}

So, I’m trying to setup a cleaner that would nil old references but I’m
lost in maps :

@semaphore.synchronize do
@workers.map{|k,v| v.map{|worker| (Time.now - worker[:started_at] > 5
&& worker[:thread].status == false) ? (cleaned +=1; nil) : worker}}
end

When condition is true, cleaned is incremented but the nil does not
replace @workers entry.

So, I did another test :
hs = {}
hs[:toto] = []
hs[:toto] << {:kk => 28, :so => ‘yes’}
hs[:toto] << {:kk => 30}
hs[:tata] = []
hs[:tata] << {:kk => 2}

hs = hs.map{|k,v| v.map {|a| a[:kk] > 28 ? nil : a} }
pp hs displays
[[{:kk=>28, :so=>“yes”}, nil], [{:kk=>2}]]

This one works right, for each hs entry, array is nilled if :kk value is

to 28

Obviously there is a mistake somewhere in the first code source but I
don’t find it.

Any help appreciated, thank you


#2

On Thu, Apr 2, 2009 at 3:19 AM, Paganoni removed_email_address@domain.invalid wrote:

@workers[:one_category] << {:started_at => Time.now, :thread => th}
replace @workers entry.
pp hs displays
Any help appreciated, thank you

@workers.map{|k,v| v.map{|worker| (Time.now - worker[:started_at] > 5 #

vs.

hs = hs.map{|k,v| v.map {|a| a[:kk] > 28 ? nil : a} }

In the first case you create a new array from the nested map calls and
then
THROW IT AWAY, @workers still refers to the old array.

In the second you compute a new array and assign it to hs.


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale


#3

On 2 Apr 2009, at 08:19, Paganoni wrote:

@workers[:one_category] = []
@workers[:one_category] << {:started_at => Time.now, :thread => th}

So, I’m trying to setup a cleaner that would nil old references but
I’m
lost in maps :

@semaphore.synchronize do
@workers.map{|k,v| v.map{|worker| (Time.now - worker[:started_at] > 5
&& worker[:thread].status == false) ? (cleaned +=1; nil) : worker}}
end

You could write something like:

def thread_dead? worker
(Time.now - worker[:started_at] > 5) && (worker[:thread].status ==
false)
end

@semaphore.synchronize do
hs.delete_if do |k, v|
v.map! { |worker| thread_dead?(worker) ? (cleaned += 1; nil) :
worker }.compact!
v.empty?
end
end

Ellie

Eleanor McHugh
Games With Brains
http://slides.games-with-brains.net

raise ArgumentError unless @reality.responds_to? :reason


#4

le 02/04/2009 09:57, Rick DeNatale nous a dit:

In the first case you create a new array from the nested map calls and then
THROW IT AWAY, @workers still refers to the old array.

In the second you compute a new array and assign it to hs.

But can I miss this sort of things for hours ???

Thanks !


#5

On 2 Apr 2009, at 21:14, Paganoni wrote:

worker }.compact!
v.empty?
end
end

Your delete_if solution is quite elegant because self explanatory !

Thank you :slight_smile:

The delete_if could also be written as a one-liner, but it looks uglier:

hs.delete_if { |k, v| (v.map! { |worker| thread_dead?(worker) ?
(cleaned += 1; nil) : worker }.compact! || v).empty? }

It always bugs me that compact! returns nil if no changes occur,
rather than the enum as I seem to use this particular idiom a lot sigh

Ellie

Eleanor McHugh
Games With Brains
http://slides.games-with-brains.net

raise ArgumentError unless @reality.responds_to? :reason


#6

le 02/04/2009 10:27, Eleanor McHugh nous a dit:

  v.map! { |worker| thread_dead?(worker) ? (cleaned += 1; nil) :  

worker }.compact!
v.empty?
end
end

Your delete_if solution is quite elegant because self explanatory !

Thanks


#7

On Fri, Apr 3, 2009 at 3:16 AM, Eleanor McHugh
removed_email_address@domain.invalid wrote:

It always bugs me that compact! returns nil if no changes occur, rather than
the enum as I seem to use this particular idiom a lot sigh

yeah, it seems like a very c-like thing to do :frowning: i’d rather have it
set a (pseudo-)global variable the way regexp matches do.

martin


#8

raise ArgumentError unless @reality.responds_to? :reason

Yes, I find it equally annoying that strip! has the same bahviour

=======================================================================
This email, including any attachments, is only for the intended
addressee. It is subject to copyright, is confidential and may be
the subject of legal or other privilege, none of which is waived or
lost by reason of this transmission.
If the receiver is not the intended addressee, please accept our
apologies, notify us by return, delete all copies and perform no
other act on the email.
Unfortunately, we cannot warrant that the email has not been
altered or corrupted during transmission.


#9

On 3 Apr 2009, at 00:13, David M. wrote:

hs.delete_if { |k, v| (v.map! { |worker| thread_dead?(worker) ?
(cleaned += 1;
nil) : worker }.tap(&:compact!).empty? }

I don’t feel strongly about compact! – after all, it may be useful
to know
whether it found anything. But this is exactly what tap is for, right?

I’ve only just started moving over to 1.9 so I’ve not used tap(), I’ll
bear it in mind for the future. To be honest though I can’t recall a
single occasion where I’ve used compact!() that I didn’t find the nil
result inconvenient and have even been known to redefine it to work
the way I prefer when it’s been frequently used in a program :slight_smile:

Ellie

Eleanor McHugh
Games With Brains
http://slides.games-with-brains.net

raise ArgumentError unless @reality.responds_to? :reason


#10

On Thursday 02 April 2009 16:46:37 Eleanor McHugh wrote:

hs.delete_if { |k, v| (v.map! { |worker| thread_dead?(worker) ?
(cleaned += 1; nil) : worker }.compact! || v).empty? }

It always bugs me that compact! returns nil if no changes occur,
rather than the enum as I seem to use this particular idiom a lot sigh

It could also be written like this, if I understand it:

hs.delete_if { |k, v| (v.map! { |worker| thread_dead?(worker) ? (cleaned
+= 1;
nil) : worker }.tap(&:compact!).empty? }

I don’t feel strongly about compact! – after all, it may be useful to
know
whether it found anything. But this is exactly what tap is for, right?

For those on 1.8.6:

class Object
def tap
yield self
self
end
end