On 2008-04-18 23:35:12 -0600, Ivan Illarionov <[EMAIL PROTECTED]> said:
> On Sat, 19 Apr 2008 04:45:54 +0000, Ivan Illarionov wrote: > >> On Fri, 18 Apr 2008 22:30:45 -0500, Grant Edwards wrote: >> >>> On 2008-04-18, Bob Greschke <[EMAIL PROTECTED]> wrote: >>> >>>> However, in playing around with your suggestion and Grant's code I've >>>> found that the struct stuff is WAY slower than doing something like >>>> this >>>> >>>> Value = (ord(Buf[s])*65536)+(ord(Buf[s+1])*256)+ord(Buf[s+2]) if >>>> Value >>>>> = 0x800000: >>>> Value -= 0x1000000 >>>> >>>> This is almost twice as fast just sitting here grinding through a few >>>> hundred thousand conversions (like 3sec vs. ~5secs just counting on my >>>> fingers - on an old Sun...it's a bit slow). Replacing *65536 with >>>> <<16 and *256 with <<8 might even be a little faster, but it's too >>>> close to call without really profiling it. >>> >>> I didn't know speed was important. This might be a little faster >>> (depending on hardware): >>> >>> Value = (ord(Buf[s])<<16) | (ord(Buf[s+1])<<8) | ord(Buf[s+2]) >>> >>> It also makes the intention a bit more obvious (at least to me). >>> >>> A decent C compiler will recognize that <<16 and <<8 are special and >>> just move bytes around rather than actually doing shifts. I doubt the >>> Python compiler does optimizations like that, but shifts are still >>> usually faster than multiplies (though, again, a good compiler will >>> recognize that multiplying by 65536 is the same as shifting by 16 and >>> just move bytes around). >> >> So why not put it in C extension? >> >> It's easier than most people think: >> >> <code> >> from3bytes.c >> ============ >> #include <Python.h> >> >> PyObject* >> from3bytes(PyObject* self, PyObject* args) { >> const char * s; >> int len; >> if (!PyArg_ParseTuple(args, "s#", &s, &len)) >> return NULL; >> long n = (s[0]<<16) | (s[1]<<8) | s[2]; if (n >= 0x800000) >> n -= 0x1000000; >> return PyInt_FromLong(n); >> } >> >> static PyMethodDef functions[] = { >> {"from3bytes", (PyCFunction)from3bytes, METH_VARARGS}, {NULL, >> NULL, 0, NULL}, >> }; >> >> >> DL_EXPORT(void) >> init_from3bytes(void) >> { >> Py_InitModule("_from3bytes", functions); >> } >> >> buildme.py >> ========== >> import os >> import sys >> from distutils.core import Extension, setup >> >> os.chdir(os.path.dirname(os.path.abspath(__file__))) sys.argv = >> [sys.argv[0], 'build_ext', '-i'] setup(ext_modules = >> [Extension('_from3bytes', ['from3bytes.c'])]) </code> >> >> 'python buildme.py' will create '_from3bytes.so' file 'from _from3bytes >> import from3bytes' will import C-optimized function >> >> Hope this helps. > > Sorry, > the right code should be: > > PyObject* from3bytes(PyObject* self, PyObject* args) > { > const char * s; > int len; > if (!PyArg_ParseTuple(args, "s#", &s, &len)) > return NULL; > long n = ((((unsigned char)s[0])<<16) | (((unsigned char)s[1])<<8) | > ((unsigned char)s[2])); > if (n >= 0x800000) > n -= 0x1000000; > return PyInt_FromLong(n); > } No thanks. Being able to alter and install these programs on whatever computer they are installed on is more important than speed. I went down the C-extension path years ago and it turned into a big mess. Everything has to run on Sun's, Mac's, Linux and Windows without any major hassels if they have to be changed. I can't reley on everything the program needs to be rebuilt being installed beyond Python and Tkinter (and pySerial and PIL for a couple of programs), which they need to run. So no compiling and everything is in one file, in case a new version has to be upgraded by a user by emailing it to them while they're sitting on some mountain in Tibet. Just unzip, stick the .py somewhere logical, (usually) double-click, and they are off and running. Bob -- http://mail.python.org/mailman/listinfo/python-list