说道Python和多线程,非常easy想到GIL,GIL意味着仅仅要是用Python做的多线程程序。就无法利用多个CPU。

经过一些失败的尝试后,我也一度觉得GIL是无解的。我们甚至把注意力转向了IronPython等无锁Python,可是实际上那样问题可能很多其它。比方我们不熟悉mono,mono也没达到全然成熟的程度。

直到skynet的QQ群里一位朋友介绍了还有一种载入so的方式,事情才有了180度的变化。

方法例如以下:

1、编译Python源代码,编译时加上參数--enable-shared,编译成so动态链接库。

2、找到so,拷贝N份。分别命名为 libpython_1.so, libpython_2.so, ... 等等

3、用C语言。使用linux下的ldfcn库。动态载入这些so库,ldfcn能够保证同名全局变量不冲突。

(C语言源代码。待整理)

#include <stdio.h>
#include "Python.h"
#include <dlfcn.h>
#include <pthread.h> #define N 5 void* h[N] = { NULL }; void thread( int index )
{
void(*py_init)();
int(*is_init)();
PyObject*(*py_import)(char*);
PyObject*(*py_getattr_bystr)(PyObject*, char*);
PyObject*(*py_call)(PyObject*, PyObject*); py_init = NULL;
is_init = NULL;
py_import = NULL;
py_getattr_bystr = NULL;
py_call = NULL; PyObject* mod = NULL;
PyObject* func = NULL;
PyObject* ret = NULL; py_init = dlsym( h[index], "Py_Initialize" );
is_init = dlsym( h[index], "Py_IsInitialized" );
py_import = dlsym( h[index], "PyImport_ImportModule" );
py_getattr_bystr = dlsym( h[index], "PyObject_GetAttrString" );
py_call = dlsym( h[index], "PyObject_CallObject" ); py_init();
mod = py_import( "hello" );
func = py_getattr_bystr( mod, "output" );
ret = py_call( func, NULL ); return;
} int main()
{
char temp[64];
int i;
int ret;
pthread_t tid[5] = {0}; for (i=0; i<N; ++i) {
sprintf( temp, "libpython/libpython3.4m_%d.so", i+1 );
//h[i] = dlopen( temp, RTLD_NOW | RTLD_DEEPBIND );
h[i] = dlopen( temp, RTLD_NOW );
} for ( i=0; i<N; ++i ) {
ret=pthread_create( &tid[i], NULL, (void *)thread, (void*)i ); // 成功返回0。错误返回错误编号
} for ( i=0; i<N; ++i ) {
pthread_join( tid[i],NULL );
} return 0;
}

(编译注意事项。待整理)

(环境变量设置,待整理)

用简单Py脚本測试。会发现脚本的执行确实是独立的。可是假设用了 import time。则会造成段错误。

原因是用这样的方法。以后import的各种python的库,假设是C语言扩展的,那么就会由于反复而冲突。

解决方法是在编译Python时,增加--enable-time,把time库和python库编译到一起。就能解决问题。(解决方法见后面)

(还有一种备选方案是找到time源代码。在库名后加上数字,也编出N份time_1, time_2... 等等。在脚本里也分别import不同的time库,就可以。)

(2015-9-3注:对这个问题的理解在本系列第六章会有深入的解答。)

因为我们的Python环境禁止在脚本内启动多线程,所以能够增加编译參数--without-threads,这样还能略微提高一点执行效率。

2015-8-26补充:

在编译python时把其它module增加同一个so:

改动 Module/Setup 文件,查找datetime。依照datetime相同的格式写上你要打包的源文件和目标名称。

被凝视的库取消凝视也能够打包。

检查是否打包成功:

用vim之类的文本编辑器,直接打开so文件,搜索keyword。比方datetime,就可以确认你的源代码是否被打包进入so。

(执行的时候注意确认,用python启动的是哪一个so,是系统的还是自己编译的。

建议每次启动都暂时改动LD_LIBRARY_PATH环境变量,避免污染系统环境。)

Python游戏server开发日记(二)绕过GIL启动多线程Python环境的更多相关文章

  1. Python游戏server开发日记(一)目标

    到了新的环境.老大让我有空研究下一代server技术,作为一个长期任务. 新的server想达到的目标: 1.分布式系统,对象(Entity)之间的关系类似于Actor模型. 2.逻辑服务,是单进程. ...

  2. Python游戏引擎开发(七):绘制矢量图

    今天来完毕绘制矢量图形. 没有读过前几章的同学,请先阅读前几章: Python游戏引擎开发(一):序 Python游戏引擎开发(二):创建窗体以及重绘界面 Python游戏引擎开发(三):显示图片 P ...

  3. Python游戏引擎开发(五):Sprite精灵类和鼠标事件

    本次来实现Sprite类和鼠标事件. 说起这个Sprite啊,涉及过2D游戏研究领域的看官应该都听说过它. 它中文原意是"精灵",只是在不同人的眼中,它所表示的意义不同. 比方说在 ...

  4. python 微服务开发书中几个方便的python框架

    python 微服务开发是一本讲python 如果进行微服务开发的实战类书籍,里面包含了几个很不错的python 模块,记录下,方便后期回顾学习 处理并发的模块 greenlet && ...

  5. 基于Golang的游戏服务器框架cellnet开发日记(二)

    看官们肯定还有大部分不是很熟悉Actor模型. 我这里基于Erlang, Skynet等语言和框架库来实战型解释下Actor模型.  Actor概念 Actor模型和OO类似, 都是符合人的思维模式进 ...

  6. python运维开发(十二)----rabbitMQ、pymysql、SQLAlchemy

    内容目录: rabbitMQ python操作mysql,pymysql模块 Python ORM框架,SQLAchemy模块 Paramiko 其他with上下文切换 rabbitMQ Rabbit ...

  7. 基于osg的python三维程序开发(二)------向量

    上一篇文章展示了如何简单创建一个osg python 程序, 本篇展示了了一些基础数据结构的使用: from pyosg import * vec = osg.Vec3Array() #push ba ...

  8. 淘宝(阿里百川)手机客户端开发日记第十篇 阿里百川服务器环境介绍之API文档的快速链接(四)

    个人感觉比较重要的快速链接: http://open.taobao.com/doc/detail.htm?id=102513 http://open.taobao.com/doc/detail.htm ...

  9. STM32F103 ucLinux开发之二(内核启动汇编代码分析)

    start_kernel之前的汇编代码分析 Boot中执行下面两句话之后,进入uclinux内核. theKernel = (void (*)(int, int, unsigned int))((ui ...

随机推荐

  1. xargs命令【转】

    本文转载自:http://man.linuxde.net/xargs

  2. sql server中的悲观锁和乐观锁

    https://www.cnblogs.com/chenwolong/p/Lock.html https://www.cnblogs.com/dengshaojun/p/3955826.html ht ...

  3. php json 初始化函数(格式化json字符串为php json_decode 标准的字符串)

    $json="[{ 'i':100000, 'u':-1,n: '中国'},{i:100001,u:-1,n:'阿尔巴尼亚'},{i:100002,u:-1,n:'阿尔及利亚',}]&quo ...

  4. [Java] 总结1.5/1.6/1.7版本的特性

    开发过程中接触到了从jdk1.5---jdk1.7的使用,在不同的阶段,都使用过了jdk的一些新特性,操作起来更加方面啦!特此总结了下,以下是测试代码: JDK1.5新特性: 1.自动装箱与拆箱: I ...

  5. linux系统在线搭建禅道

    1.先安装wget:yum -y install wget 2.下载安装禅道:[root@zhaowen ~]# wget http://dl.cnezsoft.com/zentao/9.0.1/Ze ...

  6. 二、SQL系列之~常见51道SQL查询语句

    [写在前面~~] [PS1:建议SQL初学者一定要自己先做一遍题目,这样才有效果~~(做题时为验证查询结果是否正确,可更改表中数据)] [PS2:文末最后一条代码整合了全部51道题目及答案~~] [P ...

  7. 了解php数据转json格式与前端交互基础

    php数据转json格式与前端交互 ArryJson1.php <?php $test=array(); $word=array("我12","要43", ...

  8. 项目中遇到的所有ECharts图表集合

    全放在了ECharts官网示例里面以后会一直往里面添加: https://gallery.echartsjs.com/explore.html?u=bd-2133619855&type=wor ...

  9. HBase编程 API入门系列之modify(管理端而言)(10)

    这里,我带领大家,学习更高级的,因为,在开发中,尽量不能去服务器上修改表. 所以,在管理端来修改HBase表.采用线程池的方式(也是生产开发里首推的) package zhouls.bigdata.H ...

  10. Hadoop MapReduce编程 API入门系列之计数器(二十七)

    不多说,直接上代码. MapReduce 计数器是什么?    计数器是用来记录job的执行进度和状态的.它的作用可以理解为日志.我们可以在程序的某个位置插入计数器,记录数据或者进度的变化情况. Ma ...