See also:
RubyLanguage
Hi --
I seem to keep coming up with Ruby projects that run aground on the
matter of thread safety. The most recent was the little
Object#stretch thing which extended objects module-wise for the
duration of a block. The larger earlier project that ran into the
same thing was Ruby Behaviors, which provides a way to do block-scoped
(but not thread safe) changes to core classes and modules.
I've been trying to think through the matter of thread safety
systematically. I've started to wonder whether there are different
kinds of thread safety, like there are different kinds of
infinities....
I'm not trying to argue a lax position about thread safety. I'm just
trying to understand it as deeply as I can. The difference between
Ruby code that does something and Ruby code that does something
thread-safely seems so vast; one essentially loses out on all the
conciseness of the language. At least that's my impression. Mind
you, I've done very little thread programming, which may explain why I
find the "it's not thread safe" semi-brick wall sort of exasperating,
and also may explain any deficiencies in my grasp of the
technicalities.
Anyway, here's a snapshot of my current possibly rambling thoughts --
some notes to myself, neatened up a bit. I'd be interested in hearing
what people think.
* * *
Ruby is already not thread-safe, in the sense that if you don't know
whether other threads are running, then weird things can always
happen. For example, if you do this:
obj.each { |e| puts e.upcase }
it's possible that obj.upcase will be undefined or redefined between
iterations, if you're going on the assumption that other threads might
be running and that you don't know what they will be doing.
Therefore, lack of thread safety (of this kind) is something we live
with. There may be a rogue thread out there somewhere (we assume).
So... what exactly does it mean to say that a particular practice is
not thread safe? I guess it means that the practice itself
is the
rogue thread.
But if we're planning around rogue threads -- if we always act as if
they might be there -- then theoretically shouldn't it be OK if they
are there? Or is this one of those game theory (at least the
popularized versions) questions, where A and B have to act together to
succeed but don't know what the other is doing?
Let's take Ruby Behaviors as an example. Let's say you change the
behavior of Array#join for the duration of a block:
b = Behavior.new("MyBehavior")
b.adopt do
# ... stuff ...
end
The problem here is that some other thread might be using Array#join,
and might expect it to work in the normal way.
OK, that's bad. But the question is... is it worse than the regular
conditions under which Ruby code runs? If my premise is right, every
call to Array#join
already runs the risk of taking place after some
other thread has done something weird. So what's the difference?
That's what I'm trying to figure out. Is it just quantity (i.e.,
increasing the likelihood of "something weird" going on in a distant
thread)? Or are the baseline conditions of Ruby actually less fragile
than I'm suggesting?
Of course the sensible thing to do is to declare all modifications to
core functionality to be dangerous and avoid it. That's probably
reasonable... but I just can't get away from the thought that the
changeable nature of Ruby objects, including core classes, is
something with depths that can be explored, rather than one of these
"enough rope to hang yourself" things.
Is it enough to document that something isn't thread-safe, and let
people decide whether or not to use it? Is there in fact such a thing
as absolutely knowing that multiple threads will not be running?
This is all very fragmentary but I'm just trying to stir up and
(eventually :-) clarify my thoughts on the subject.
David
David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav
On Sun, 8 Dec 2002 18:04:54 +0200, "The Dude" <noreply@sourceforge.net> wrote:
Is there a way to get these 3 results by making just one
mysql query instead of these 3 queries?
$res = mysql_query("select count(user_id) from {$tables['users']}");
$arr = mysql_fetch_array($res);
$stats['usernum'] = $arr[0]; // total number of users
mysql_free_result($res);
$res = mysql_query("select count(user_id) from {$tables['users']} where
user_active='".USER_ACTIVE."'");
$arr = mysql_fetch_array($res);
$stats['useractive'] = $arr[0]; // number of active users
mysql_free_result($res);
$res = mysql_query("select count(user_id) from {$tables['users']} where
user_active='".USER_DISABLED."'");
$arr = mysql_fetch_array($res);
$stats['userdisabled'] = $arr[0]; // number of disabled users
mysql_free_result($res);
mysql> select * from user;
+---------+---------------+
| user_id | user_active |
+---------+---------------+
| 1 | USER_ACTIVE |
| 2 | USER_ACTIVE |
| 3 | USER_DISABLED |
| 4 | USER_DISABLED |
| 5 | USER_DISABLED |
+---------+---------------+
5 rows in set (0.01 sec)
mysql> SELECT SUM(1) AS total_users,
-> SUM(CASE
-> WHEN user_active = 'USER_ACTIVE' THEN 1
-> ELSE 0
-> END) AS active_users,
-> SUM(CASE
-> WHEN user_active = 'USER_DISABLED' THEN 1
-> ELSE 0
-> END) AS disabled_users
-> FROM user
-> ;
+-------------+--------------+----------------+
| total_users | active_users | disabled_users |
+-------------+--------------+----------------+
| 5 | 2 | 3 |
+-------------+--------------+----------------+
1 row in set (0.01 sec)
--
Andy Hassall (andy@andyh.org) icq(5747695) http://www.andyh.org
http://www.andyhsoftware.co.uk/space | disk usage analysis tool
----
Can some[one] briefly compare raise and throw for me? Thx!
"raise" raises an error/exception (whatever you want to call it). This
exception - which is an object - is "rescued" later and some error-handling
code performed.
"throw" throws a symbol out into the wilderness, hoping that someone will
"catch" it.
There are distinct similarities in their operation, the most important one
being that they can jump the boundaries of several method invocations (stack
frames) at once. There are probably differences too, but to me, the real
difference is of intent. "raise/rescue/ensure" is for exception handling, and
"throw/catch" is for signalling - generally signalling that something has
finished early and we can quite the whole operation altogether.
The other difference is that I've never used throw/catch, and consider it a bit
dodgy. raise/resuce/ensure, OTOH, I use all the time.
See Pickaxe for more information.
Gavin
Hi,
In message "(Top-level "functions" == private methods).is_evil?"
on 02/12/07, Mauricio Fernández
writes:
|I was recently quite surprised to find that top-level "functions" are
|actually private instance methods of Object, for I really expected them to be
|singleton methods (see http://www.ruby-talk.com/blade/57607). This seemed
|"unclean" to me from the beginning, because I saw that this would mean
|that all Ruby objects were getting strange private methods, but OTOH
|nothing seemed to be wrong as the public interface was not modified,
|and these methods were shadowed by new ones.
"functions" cannot be singleton methods of the top-level object. If
they were singleton methods, how do you "print" inside of a method,
for example?
They are evil, as you said. But I have no better alternative idea.
Any other "function" ideas make Ruby too complex. I had to
compromise.
matz.
I have a system at the moment where I create 'things' based on a base
class SceneObject?, these 'things' have a Proc associated with them that
gets called to produce a different representation of the 'thing' (in my
case data to be passed to a 3D renderer). At the moment it all works
like this...
class SceneObject
def initialize(&generate)
@generate = generate
end
def render
self.instance_eval(&@generate)
end
end
class MyObject < SceneObject
def initialize
super() do
# Render some objects
end
end
end
a = MyObject.new
a.render
This all works, but I'd like to 'hide' the class definition stuff, the
reason being that the data files passed through this system will be
defined outside, and don't need to look like Ruby code, they 'use'
Ruby code to do the procedural stuff, but other than that I want them
to appear as simple as possible, so hiding classes, inheritance,
initialisation functions etc. would be a big benefit. Ideally I'd like
to do something like this, but can't...
def defineClass(name,&generate)
eval <<-"end_eval"
class #{name} < SceneObject
def initialize
super(&#{generate})
end
end
end_eval
end
Then in my data files use this function like so...
defineClass("MyObject") do
# Render some objects
end
a = MyObject.new
a.render
Can anyone offer any advice on how to achieve something like this?
Cheers
PaulG?
This is with ruby 1.7
pigeon% cat b.rb
#!./ruby
class SceneObject
def initialize(&generate)
@generate = generate
end
alias init initialize
def render
instance_eval(&@generate)
end
end
def defineClass(name, &block)
Object.const_set(name, Class.new(SceneObject)).instance_eval do
define_method(:initialize) { init(&block) }
end
end
defineClass("MyObject") do
puts "render some object"
end
a = MyObject.new
a.render
pigeon%
pigeon% b.rb
render some object
pigeon%
Guy Decoux
I've been looking through the generator threads in the archive, and
they all seem to centre around the problem of converting an internal
iterator to an external iterator. This would be a wonderful thing, I
admit, but so far there's been no time and space efficient way to do
it (as far as I've seen, you either need to dump the enumerable to an
array, or use call/cc).
Leaving aside the general problem for the minute, it might be useful
to see where we can efficiently write
g = <nop>SimpleGenerator.new(a) # should be space-efficient
i = g.next # should be O(1) and cheap
and where the generator iterates over the sequence nondestructively,
so that it is threadsafe. One could use g.val rather than g.next,
depending on how you think of it.
SimpleGenerator.new would most likely need to be a factory that
instantiated more specific per-type generators. Some easy examples for
generator-generating objects:
- arrays and other structures that support a[i] where i is an integer (initialize sets @i = -1, and .next does an @i+=1, @array[@i].dup)
- functions on integers (.next returns f(@i))
- sequences where f[i+1] = g(f[i], f[i-1], ..) and which don't depend on too large a history (the Fibonacci sequence, e.g., or a random number generator)
- generator-only structures like unbounded lists and circular arrays
Another nice possibility is built-in support for parallel iteration on
generatable structures:
gen = <nop>SimpleGenerator.new (a,b,c,d) {|a,b,c,d| [[a,b],c+d]]}
where gen.next returns [a.next,b.next,c.next,d.next] if no block is
given, and passes it into the block if it is. The arguments could be
automatically converted to generators if they were of some generatable
type, which allows freely mixing generatables and anything else
responding to .next. Of course, this runs into the same problems as
zip does when one of the generators runs out before the others do.
Further ideas:
Composition:
- g1 + g2 returns a generator that iterates over first g1 and then g2
- g1 || g2 iterates in parallel over g1 and g2 (confusable with or? better name? perhaps [g1,g2] would be clearer, but we can overload SimpleGenerator#|| and not just plain [], so it'd be
- gen = SimpleGenerator.create([g1+g2, g3+g4]) versus
- gen = (g1+g2)||(g3+g4)
Filtering: have an optional filter function (via .filter), so that
next calls itself repeatedly until the filter succeeds.
#each: converting an external to an internal iterator is fairly
trivial, though there would, of course, be issues with circular and
infinite generators.
Implementation shouldn't be too hard - I'll put something up on the
wiki when I get a free moment. Comments? Has anyone done something
like this already?
martin
Hello,
I defined an iterator and tried using it and got a "no block given" error. I don’t understand why I got this error because I did define a block. The yield statement is in the replace_text function and the iterator is called in the remove_destroy function.
Thank you,
Brian Takita
def replace_text(dir_name = '.')
#raise "No Block" unless block_given?
d = Dir.new(dir_name)
d.each{|x|
if x == '.' || x == '..'
next
end
if FileTest.directory?(x)
puts dir_name + '--' + x
Dir.chdir(x)
replace_text()
Dir.chdir('..')
else
if x =~ /(\.php)/
puts dir_name + '->' + x
f = File.new(x)
content = ''
f.each_line { |line|
yield line
content += line
}
f.close
f = File.new(dir_name + '/' +x, 'w+')
f.write(content)
f.close
end
end
}
d.close
end
def remove_destroy()
replace_text { |line|
if line =~ /.*->destroy\(\).*\n/
line = ""
end
}
end
remove_destroy()
Thank you for your help Guy.
I solved the recursion problem by replacing
replace_text()
With
replace_text() { yield }
Sincerely,
Brian Takita
-- DaleBrayden - 19 Nov 2002