Threading
Thomas Jensen
thomasNO at SPAM.obscure.dk
Thu Nov 15 05:04:36 EST 2001
David Bolen <db3l at fitlinxx.com> wrote in
news:ur8r024it.fsf at ctwd0143.fitlinxx.com:
> Thomas Jensen <thomasNO at SPAM.obscure.dk> writes:
> When in doubt, that's the right approach. You might be able to
> eeek a little more performance out of hand tuning some "safe"
> scenarios, but I don't think the potential downsides are worth it
> in general.
I guess you're right :-)
>> Is there any "rule-of-thumb" (or doc) regarding which operations
>> are atomic, for example is the following safe:
>
> An operation would be atomic with respect to Python interpreter
> threads if it executes while holding onto the GIL (global
> interpreter lock). Generally speaking this must (a) be something
> written in C, either as part of the interpreter or an extension
> module, and (b) not release the GIL to provide for threading
> execution around a long running or blocked activity, such as I/O.
Ahh, the GIL, thought I'd heard about such a beast.
> Generally, it's just safer to lock more conservatively.
I'll do that.
>> thread 1:
>> mylist.reverse()
>>
>> thread 2:
>> for item in mylist: ...
>>
>> (silly example perhaps)
>
> This doesn't appear as it would be safe if the goal of thread 2 was
> to iterate through every item in the list consistently. If mylist
That would most probably be the goal.
> was a builtin list type object (and at least in the CPython
> implementation) then you are guaranteed that once it begins, the
> reverse() method call in thread 1 will run to completion before any
> other Python thread continues execution. What you aren't
> guaranteed is how that reverse call's timing will occur with
> respect to thread 2.
>
> So if thread 1 managed to transfer control to the reverse() method
> prior to thread 2 hitting that for loop, you'd get a consistent
> (reverse) list.
>
> But if thread 1 didn't make it into the call until thread 2 was
> partially through the loop, then the list would be reversed, and it
> would be equivalent to having Python code that mutated the list
> within the for loop, in which case behavior is non-deterministic
> (at least in general, since it depends on the type of mutation).
>
> Since the mutation in this case keeps the list the same length but
> just reverses the contents, I expect you'd have entries processed
> in the for loop up until the thread context switch, and then you'd
> get the entries in the remaining positions of the list but for the
> reversed copy.
That would probably not be the goal.
> I'd definitely protect something like this - you've clearly got
> higher level processing (the iteration over the list) that needs
> the list to remain intact during the work. Either that, or protect
> the act of making a copy of the list, and then iterate over that
> copy. The copying is one of those potential tuning points - I'd
> have to double check, but I bet that an operation like "newlist =
> mylist[:]" would be atomic, so you could probably get away with not
> protecting that. At least until mylist happened to end up a user
> class with its own __getslice__.
Thank you for the detailed explanation, I guess the reason I asked was
that I didn't quite know how the GIL worked.
I thought that perhaps the for loop would lock the specific list for
modification. The more I think about it, the more unreasonable it
seems. Especially since the lock is global, it would not only block
access to the list.
I'll keep up the paranoia :-)
--
Best Regards
Thomas Jensen
More information about the Python-list
mailing list