Aahz> Skip Montanaro wrote: >> The number of tracked objects should be relatively small. All active >> frames of all active threads could conceivably be tracking objects, >> but this seems small compared to the number of functions defined in a >> given application. Aahz> Hmmm? That doesn't seem quite right to me. That's just a Aahz> knee-jerk reaction, I don't have any real evidence. Here's my rationale. Perhaps I've goofed somewhere. TRACK_OBJECT and UNTRACK_OBJECT opcodes will only be inserted in the bodies of functions. Functions are only considered active when there is an active (but possibly suspended) eval_frame call on the C stack that is executing that function's byte code. Suppose my module is def a(): print "a" def b(): print "b" a() def c(): print "c" b() At the point where a's print statement is executed, functions a and b are active. Function c is not. This reasoning applies on a per-thread basis. So the number of active functions by my definition is the number of times eval_frame appears on the call stack for all active threads. In most situations that will be far less (barring deep recursion) than the number of functions available to the application. All I guess I'm trying to communicate is that object tracking is a dynamic thing, not a static thing. Aahz> As a side note, I'm not sure whether some mention should be made Aahz> that TRACK_OBJECT specifically does not work any differently from Aahz> current Python when it comes to threads. That is, if it's a Aahz> shared variable of any sort, you need a mutex if you're going to Aahz> perform multiple operations on it. That's true. If a global object is shared among multiple threads, access to it must still be protected. I haven't added anything to the mix in that regard. I'll add a short section on threads. Hmm... What about this (dumb) code? l = [] lock = threading.Lock() ... def fill_l(): for i in range(1000): lock.acquire() l.append(math.sin(i)) lock.release() ... def consume_l(): while 1: lock.acquire() if l: elt = l.pop() lock.release() fiddle(elt) It's not clear from a static analysis of the code what the lock is protecting. (You can't tell at compile-time that threads are even involved can you?) Would or should it affect attempts to track "l.append" or "math.sin" in the fill_l function? If we annotate the code with mythical track_object and untrack_object builtins (I'm not proposing such functions (they can't be implemented with Python's call-by-value semantics), just illustrating where stuff would go in the bytecode), we get l = [] lock = threading.Lock() ... def fill_l(): track_object("l.append", append) track_object("math.sin", sin) for i in range(1000): lock.acquire() append(sin(i)) lock.release() untrack_object("math.sin", sin) untrack_object("l.append", append) ... def consume_l(): while 1: lock.acquire() if l: elt = l.pop() lock.release() fiddle(elt) Is that correct both with and without threads? Skip
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4