On 08/18/2011 08:39 AM, Dag Sverre Seljebotn wrote:
On 08/17/2011 09:21 PM, Robert Bradshaw wrote:
On Wed, Aug 17, 2011 at 11:46 AM, Dag Sverre Seljebotn
<d.s.seljeb...@astro.uio.no> wrote:
On 08/17/2011 08:19 PM, Robert Bradshaw wrote:
That's a nice idea. I have to admit that all these special gil
declarations are a bit messy. I'd also rather introduce clear
decorators, e.g.
@cython.requires_gil # expects gil
cdef a(): ...
@cython.requires.gil(False) # nogil
cdef b(): ...
@cython.aquires_gil # with gil
cdef c(): ...
(Actually, now that we have the "with gil" statement, it could be
worth considering simply noticing the pattern of the entire function
body in a with gil block/as the first statement and acquiring the GIL
before argument parsing.)
Note that we need to declare functions as requiring the GIL to allow
for declaring cpython.pxd if extern functions are implicitly nogil.
I agree, it's messy in the current situation, simplifying would be good.
Assuming we can't acquire the GIL in every single function just to be
sure,
I have a hunch that the "acquires_gil" aspect of a function is just
declared
in the wrong place. I mean, the same function might be passed as a
callback
to C both while holding the GIL and while not holding the GIL -- it
would be
nice to automatically wrap it in a GIL-acquiring wrapper only when
needed.
So to me it makes more sense to have acquires_gil be part of function
pointer types, or of the C call where the pointer is passed, or similar.
Sort of like an FFI. Can't think of a practical scheme that's more
user-friendly than the current way though...
I was thinking the opposite, "aquires_gil" should be completely
transparent to the caller (assuming it's cheap enough to
check-or-acquire, but that's an optimization not API issue). On the
other hand requires/does not require does need to be visible to the
caller though, which argues for it being part of the signature.
Are you saying that every single function cdef function, ever, that are
not "nogil" should have acqusition semantics?
Those semantics would be great, but I worry a bit about performance --
we just agreed to make function GIL-acquisition even a bit more
expensive with that check...
Hmm. How about this:
i) Every cdef function that needs the GIL to be held generates a
GIL-acquiring wrapper function as well.
ii) Whenever taking the address of such a function, you get the address
of the GIL-requiring wrapper, which can safely be used from any code,
whether holding the GIL or not.
iii) However, Cython code that already holds the GIL can call the inner
function directly, as an optimization. Should be possible to do this
across pxd's as well.
iv) We may introduce a cython.nogil_function_address or similar just to
provide an option to get around ii).
v) The "with gil" on functions simply ceases to take effect, and is
deprecated from the language.
Relevant benchmarks on my laptop:
Calling an almost-noop cdef function (in a loop): 0.7 ns per call
Calling same function with "with gil": 58 ns per call
A dict lookup + Python integer-object addition: 57 ns per iteration
I think the cost (basically 2 python ops) is too high to go for the
simpler scheme of simply making everything "with gil" that is not
"nogil"? Also, the GIL-initialization check will make it even more
expensive.
cdef int noop(int i) nogil:
return 2 * i
cdef int withgil(int i) with gil:
return 2 * i
def call_noop(int reps):
cdef int i
cdef int s = 0
for i in range(reps):
s += noop(i)
return s
def call_withgil(int reps):
cdef int i
cdef int s = 0
for i in range(reps):
s += withgil(i)
return s
def call_dict(int reps):
cdef int i
cdef object s = 0
for i in range(reps):
s += d['2']
return s
d = {}
for i in range(15):
d[str(i)] = i
Dag SVerre
_______________________________________________
cython-devel mailing list
cython-devel@python.org
http://mail.python.org/mailman/listinfo/cython-devel