From: Thomas Enebo Date: 2008-12-04T02:52:03+09:00 Subject: [ruby-core:20262] Re: autoload and concurrency Charles Oliver Nutter wrote: > Yehuda Katz wrote: >> Merb uses autoload rather extensively. We have lately observed some >> disturbing behavior around concurrency. >> >> Effectively, because autoload removes the flag before loading the >> file, if two threads concurrently attempt to access an autoloaded >> constant, one of the threads can get a NameError. >> >> It's easy to reproduce this by adding a sleep to the file being >> loaded before the constant is defined, and then spinning up two >> threads that both try to use the constant. This is reproducible in >> MRI; it does not only happen with JRuby's true parallel execution. >> >> The worst part is that no user action can solve this problem: because >> autoloading is magic, it's impossible for the user to lock the >> resulting require. In effect, this makes autoloading completely >> useless for threaded environments. Is this intentional? >> >> Is there something we can do at the language level to ameliorate this >> problem? > > I've spent some time looking into this on Yehuda's behalf, and I > believe there's no way to make this work without a behavioral change > to autoload. > > Autoload is part of the normal constant lookup scheme. When defining > an autoload, a special value is inserted into the target constant > table with autoload file information. As constants are looked up, if > one of these special values is encountered an autoload is triggered. > > Currently, the basic logic of autoload is like this: > > 1. The special value is removed from the constant table > 2. The associated file is required, and presumably defines the constant > 3. The constant is re-looked-up after the require completes > > The problem lies in step 1 here. There can be a gap between the time > the special value is removed from the constant table and the time the > required file redefines it. During this period, another thread may try > to request the constant value. Since the autoload value has been > removed and the new value has not yet replaced it, the constant search > continues (and eventually fails with a NameError). > > The primary behavioral change needed would be to not remove the > autoload value, or to replace it with a new marker indicating > "autoload in progress". This would require changes to anything that > looks up constants, so it would know not to initiate a new autoload > require nor continue up the constant scope chain but to *block* until > the autoload is complete. I believe this is the only way to make > autoload threadsafe. The other wrinkle in this is that the autoload itself may make a check against that constant (perhaps this is uncommon). So the autoload thread and any child threads of the autoload thread should actually see it as undefined. > > I will also agree with Yehuda that a thread-unsafe autoload is broken, > since it means the primary use case of autoload (delayed loading a > file and definition of a constant) can't be used in the presence of > threads. Dare I say that merb and Rails 2.3 should reconsider autoload as a reasonable method for lazy loading. There has to be an explicit thread-safe way of lazy loading which does not look bad. -Tom