借助Cinpy和C语言解释器TinyCC,可以在python程序里面直接嵌入C语言片断、不经编译直接使用C编写的函数了。
win2k平台上,简单的测试对比数据如下(递归方法计算第四十项兔子数列fib(40))
语言 |
实现 |
时间 |
评 | |
python | 官方python 2.4.3 | 纯python fib函数 | 568.718 | 天啊 |
使用psyco加速的python fib函数 | 17.922 | 比较接近,还行 | ||
使用swig直接转换的C语言编写的模块 | 13.453 | |||
使用Cinpy嵌入fib函数 | 11.532 | |||
C | VC6 | 速度优化编译的可执行文件 | 5.562 | |
TinyCC 0.9.23 | 编译的可执行文件 | 6.719 | ||
解释执行 | 6.813 | |||
FreeBASIC | fbc 0.16b | 编译的可执行文件(-arch 486) | 8.022 | |
编译的可执行文件(-arch 686) | 7.619 | |||
forth | 4th 3.5a2 | 4th cx fib.4th | 277 | 这个表现太失望了 |
4th csv fib.4th fib.hx 4th lx fib.hx |
196 | |||
4th lg fib.hx fib.c mingw -O2 fib.c -o fib.exe |
110 | |||
gforth-0.6.2 | Gforth-fast fib.gfth | 14.719 | 不错,不过不是说和C的速度可以比嘛? 怎么也就是优化的python的速度啊 |
注:
function fib(x as integer) as integer if x<=1 then return 1 else return fib(x-1) + fib(x-2) end if end function dim starttime, endtime as double dim res as integer starttime=timer res=fib(40) endtime=timer print "fib(40)= ";res print "time elapsed: "; (endtime-starttime); " s"
: fib ( x -- y ) dup 2 > if dup 1 - recurse swap 2 - recurse + exit then drop 1 ; time 41 fib . cr time swap - ." time elapsed " . ." s" cr
: fib ( x -- y ) dup 2 > if dup 1 - recurse swap 2 - recurse + exit then drop 1 ; utime 41 fib . cr utime 2swap d- ." time elapsed " d. ." us" cr
Doug Currie在tcc的邮件列表里面提供了一个补丁:
Here is what I did (and reported to the mailing list) last February,
so the patch may not be accurate for more recent versions, but the
issues are the same...
I have been able to create a libtcc.dll for WinXP using MinGW/MSYS;
the changes that were necessary were very minor. Perhaps this
description will help others use libtcc on Windows.
First, a small bug to report:
In tcc.c the function tcc_basename() follows the line:
#if !defined(LIBTCC)
but the function tcc_basename() is used in pe_build_exports() in
tccpe.c -- moving the #if line below the function tcc_basename()
eliminates a link error building libtcc.dll in PE target mode.
Second, configuring and making tcc with MSYS places a pathname in
config.h in MSYS format. For example, I passed the argument
--prefix=/c/Dev/tcc
to configure; this path was good for building tcc.exe and didn't
contain any spaces, unlike the default path. This creates the line
#define CONFIG_TCCDIR "/c/Dev/tcc"
in config.h. Manually changing this line to
#define CONFIG_TCCDIR "C:/Dev/tcc"
enables libtcc.dll to find the include files and libraries once the
library is built. [The application tcc.exe avoids this problem by
setting tcc_lib_path from the application's directory at startup. A
similar solution could be used for the library using DllMain.]
So, after configure, fix CONFIG_TCCDIR in config.h and make.
Finally, the library libtcc.dll can be built with the MSYS command:
gcc -O2 -shared -Wall -Wl,--export-all-symbols /
-mpreferred-stack-boundary=2 /
-march=i386 -falign-functions=0 -fno-strict-aliasing /
-DTCC_TARGET_PE -DLIBTCC -o libtcc.dll tcc.c
Below is a diff of tcc-0.9.23 tcc.c and the changes for LIBTCC with
TCC_TARGET_PE and DLL location of library files.
Regards,
e
$ diff -u ../tcc-0.9.23-o/tcc.c tcc.c
--- ../tcc-0.9.23-o/tcc.c Fri Jun 17 18:09:15 2005
+++ tcc.c Tue Feb 28 17:03:44 2006
@@ -10157,8 +10157,6 @@
flag_name, value);
}
-#if !defined(LIBTCC)
-
/* extract the basename of a file */
static const char *tcc_basename(const char *name)
{
@@ -10175,6 +10173,35 @@
return p;
}
+#if defined(LIBTCC)
+
+#ifdef WIN32
+int __stdcall DllMain(void * hinstDLL, unsigned long fdwReason, void *
lpvReserved)
+{
+ if (fdwReason == 1/*DLL_PROCESS_ATTACH*/)
+ {
+ /* on win32, as implemented in main()
+ we suppose the lib and includes are at the location of this library
+ */
+ static char path[1024];
+ char *p, *d;
+
+ GetModuleFileNameA(hinstDLL, path, sizeof path);
+ p = d = strlwr(path);
+ while (*d)
+ {
+ if (*d == '//') *d = '/', p = d;
+ ++d;
+ }
+ *p = '/0';
+ tcc_lib_path = path;
+ }
+ return 1 /*TRUE*/;
+}
+#endif
+
+#else /* !LIBTCC */
static int64_t getclock_us(void)
{
#ifdef WIN32