什么是Unix Domain Socket

基于socket的框架上发展出一种IPC机制,就是UNIX Domain Socket。虽然网络socket也可用于同一台主机的进程间通讯(通过loopback地址127.0.0.1),但是UNIX Domain Socket用于IPC更有效率:

  • 不需要经过网络协议栈
  • 不需要打包拆包、计算校验和、维护序号和应答等

只是将应用层数据从一个进程拷贝到另一个进程。这是因为,IPC机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。UNIX Domain Socket也提供面向流和面向数据包两种API接口,类似于TCP和UDP,但是面向消息的UNIX Domain Socket也是可靠的,消息既不会丢失也不会顺序错乱。

应用

UNIX Domain Socket是全双工的,API接口语义丰富,相比其它IPC机制有明显的优越性,目前已成为使用最广泛的IPC机制,比如X Window服务器和GUI程序之间就是通过UNIX Domain Socket通讯的。

Nginx通过unix:/socket与fastcgi连接,提升性能,比tcp socket要高效

  • 在nginx.conf中修改配置为:
1
2
fastcgi_pass unix:/tmp/php-cgi.sock;
#fastcgi_pass 127.0.0.1:9000;
  • 在php-fpm.conf中修改配置为:
1
/tmp/php-cgi.sock

通信过程

用Unix domain socket写的Demo

使用UNIX Domain Socket的过程和网络socket十分相似,也要先调用socket()创建一个socket文件描述符,address family指定为AF_UNIX,type可以选择SOCK_DGRAM或SOCK_STREAM,protocol参数仍然指定为0即可。通常是指定/tmp/目录下的一个文件作为通信路径

源码demo链接

收藏一些不错的文章

在豆瓣阅读到一些好的文章,通常会点击加心喜爱。久而久之,就淡忘了,于是想把他们下载下来,用了一天的时间写了具有爬虫和分析功能的下载器。使用了BeautifulSoup,urllib模块.可以一次性抓取其他人的文章。

使用方法:

1
2
3
4
5
6
7
8
if __name__ == "__main__":
#用户名,可以写入douban ID
usrnames = ["laiyonghao","fenng"]
for name in usrnames:
cwl = Crawler(name)
cwl.start()
parser = Parser(cwl)
parser.run()

运行 python main.py

结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
tmp
├── fenng
│ ├── Got talent?
│ ├── QCon Beijing 2013 乱记
│ ├── 北京生存指南
│ ├── 发现「讷客」
│ ├── 父亲谈创新
│ ├── 和菜头对豆瓣用户骂声的回应
│ ├── 胡扯两句
│ ├── 年会:公司人的新民俗
│ ├── 一个关于嘲笑的小故事
│ ├── 有些事,蹲在家里是永远实现不了的。
│ ├── 赞
│ └── 中国说唱教父--尹相杰<转>
└── laiyonghao
├── Live Together, Hate Each Other
├── 当初的愿望实现了么?
├── 豆瓣阅读即将开售(已上线)
├── 婚礼主题曲背后的故事
└── 科普也需严谨---对《数学之美》密码部分的评论

源代码链接
Happy Hacking : )

python拓展编写

C++编写python的拓展。提高程序运行效率
我理解的一般流程:

  • 编写自己的业务逻辑代码本例子如
1
string add(int a,int b)
  • 包装为python函数,用于解析python传进来的参数
1
2
3
4
5
PyObject* wrap_add(PyObject* self,PyObject* args);
//解析参数
PyArg_ParseTuple(args,"i|i",&a,&b);
//构建返回值
Py_BuildValue("s",add(a,b).c_str());
  • 编写映射函数
1
2
3
4
5
static PyMethodDef bintMethods[] =
{
{"add", wrap_add, METH_VARARGS, "For add"},
{NULL, NULL,0,NULL}
}

*.模块初始化函数

1
2
3
4
5
void initbint() {
PyObject* m;
m = Py_InitModule("bint", bintMethods);
}

如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include "BigNum.h"
#include <python2.7/Python.h>
#include <iostream>

string add(int a,int b) {
Bint num1(a);
Bint num2(b);
Bint ans = num1 + num2;
return Bint::write(ans);
}

string multiple(int a,int b) {
Bint num1(a);
Bint num2(b);
Bint ans = num1 * num2;
return Bint::write(ans);
}

PyObject* wrap_add(PyObject* self,PyObject* args) {
int a,b;
if (!PyArg_ParseTuple(args,"i|i",&a,&b))
return NULL;
return Py_BuildValue("s",add(a,b).c_str());
}

PyObject* wrap_mul(PyObject* self,PyObject* args) {
int a,b;
if (!PyArg_ParseTuple(args,"i|i",&a,&b))
return NULL;
return Py_BuildValue("s",multiple(a,b).c_str());
}

static PyMethodDef bintMethods[] =
{
{"add", wrap_add, METH_VARARGS, "For add"},
{"mul", wrap_mul, METH_VARARGS, "For mul"},
{NULL, NULL,0,NULL}
};

extern "C" //不加会导致找不到initbint
void initbint() {
PyObject* m;
m = Py_InitModule("bint", bintMethods);
}

编译成动态链接库

1
2
3
4
all:
g++ -fPIC -shared BigNum.cpp -o Bint.so
clean:
rm -rf bint.so
1
2
import bint
bint.mul(4000000,5000000)

GitHub上有源码

C++调用Python

python的开发效率之高是毋庸置疑的,C++/C的语言性能之快也是让人羡慕的。这一次,鱼和熊掌是可以兼得的 :),混合编程,使得我们可以取之所长,游走在C与python之间。很多游戏开发中使用python来实现战斗脚本。

  • 初始化调用
    Py_Initialize();

  • PyObject* PyImport_ImportModule (char *name)
    一般都是通过(pmod = PyImport_ImportModule (“zhengji.app_context”)先来
    加载一个模块(py脚本),得到一个PyObject *pmod对象,失败返回NULL类型

  • 获取某个方法或者类,PyObject * o是pmod
    PyObject* PyObject_GetAttrString (PyObject *o, char *attr_name)

调用该方法 callable_object是第二步返回的指针
PyObject
PyObject_CallFunction (PyObject *callable_object, char *format, …)

  • 将PyObject* 返回char*
    char* PyString_AsString (PyObject *string)

  • 结束初始化
    Py_Finalize();

下面是script.py的内容

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/python
# Filename: script.py
class Student:
def SetName(self,name):
self._name = name
def PrintName(self):
print self._name
def hello():
print "Hello World\n"
def world(name):
print "name"

C++调用Script.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <python2.7/Python.h>
#include <iostream>
#include <string>

int main () {

//使用python之前,要调用Py_Initialize();这个函数进行初始化
Py_Initialize();

PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')");

PyObject * pModule = NULL;
PyObject * pFunc = NULL;
PyObject * pClass = NULL;
PyObject * pInstance = NULL;

//这里是要调用的文件名
pModule = PyImport_ImportModule("script");
//这里是要调用的函数名
pFunc= PyObject_GetAttrString(pModule, "hello");
//调用函数
PyEval_CallObject(pFunc, NULL);
Py_DECREF(pFunc);

pFunc = PyObject_GetAttrString(pModule, "world");
PyObject_CallFunction(pFunc, "s", "zhengji");
Py_DECREF(pFunc);

//测试调用python的类
pClass = PyObject_GetAttrString(pModule, "Student");
if (!pClass) {
printf("Can't find Student class.\n");
return -1;
}
pInstance = PyInstance_New(pClass, NULL, NULL);
if (!pInstance) {
printf("Can't create Student instance.\n");
return -1;
}
PyObject_CallMethod(pInstance, "SetName", "s","my family");
PyObject_CallMethod(pInstance, "PrintName",NULL,NULL);
//调用Py_Finalize,这个根Py_Initialize相对应的。
Py_Finalize();
return 0;
}

编译C++代码

1
g++ zj.cpp -o zj -lpython2.7

输出结果

1
2
3
4
zj@hp:~/tmp/CcalPy$ ./zj
Hello World
name
my family

关于博客

大二那年从《暗时间》里,看到刘未鹏说“写博客很重要”,之后便开始建站写文章,Fenng君说到的文案的力量也让我深思技术人员必须要有好的文笔。一篇文章,能否做到干练,条理分明,甚至排版清晰,都是很考验人的。以后文章不能令自己满意,(就像自己开发的产品你都不喜欢使用)绝不能发表。

今天好好地修理一翻博客,顿觉从建博至今,写了很多垃圾文章,甚发觉以前很幼稚(包括想法与文字),本想删除劣迹,但这些文章终究是自己一步步成长的印记,所以让它们保留着。折腾了一天wp源码(修改css代码,添加一些有用的插件)还是很欢乐的。得益于广泛阅读和折腾,技术的广度是够的,但深度却明显不足。后续宁愿慢点也要做深度思考,尽可能写出博文。

关于技术

以后这个博客记录的更多会是后端开发的感悟,来源于自己浓厚的兴趣使然,喜欢服务端编程。虽然我在TX没有机会接触这样的开发(多少有些遗憾吧,但我希望去大公司开拓眼界,以后真的能做这样的工作,故不能放弃积累)。全凭一腔热血和毅力折腾,我所做的方法是,查看前人的技术成长,自己给自己提需求(比较傻)。偶有所得便会放上Github。诚如我所言,深度思考,学过的理要尽可能实现出来。宁愿慢点以获得真正的收获!

如今已不再觉得学习某些技术会很厉害,真正具备的是思考,学习的能力。这都离不开扎实的基础!欣喜的是,我发现只要你去尝试并坚持努力,这些都可以提高的。

接触到身边很多程序员:”CopyCat,重复劳动,眼界狭隘,缺乏思考”,内心感到难受。@ruitao说过;”不可能要求这世界所有人都有一样的想法,他们已经被磨去了棱角。“ (PS:@ruitao是一个Geek&&工具控,我的偶像:))。所幸的是我可以自我修炼,信息的畅通大大降低了学习门槛,一直欣赏一种人,知道自己需要什么并坚持想法的去学习,不为了所谓“外部评价”。很感恩认识到一些爱好技术,追求效率的朋友,和志同道合的人分享是件很幸福的事.

致将要逝去的大学时光

这个月与好友们泡在一起,俺学会了lol,虽然绝对菜B,但仍能感受到大伙在一起的狂欢激情。这些日子,我尽可能地尝试以前想做的事情,比如弹起吉他。感觉人生又完满了一点。认识多了几个热爱搞技术的朋友,能和他们一起侃共同的话题真的很爽。或许因为大家都有不安分的心以及共同的愿景吧。
转入正题:leveldb的内存设计思想

在研究leveldb的源代码,觉得他的内存池实现很收启发。学习leveldb的内存设计思想。

如果是频繁的申请内存,不连续,会造成内存碎片。但Leveldb采用了内存池的概念,一次性申请4M的内存。下次读取的内存小于内存池的容量,直接获取,否则,重新申请内存块:

  • 如果申请的字节数,bytes >= 1M,则申请内存为 bytes的块,避免内存块浪费
  • 如果申请的字节数,bytes <= 1M,则申请内存为 4M 的块
    Github 源码

阅读完《Google C++ Style》记录些小要点,很多开源代码都是按照这个规则编码,在了解这些原则之后,个人感觉阅读开源代码应该会省很多力气。

  • 有头文件都应该使用 #define 防止头文件被多重包含, 命名格式当是: _H

  • 能用前置声明的地方尽量不使用 #include
    前置声明是为了降低编译依赖,防止修改一个头文件引发多米诺效应; 举例说明: 如果头文件中用到类 File, 但不需要访问 File 类的声明, 头文件中只需前置声明 class File; 而无须 #include “file/base/file.h”.

  • 只有当函数只有 10 行甚至更少时才将其定义为内联函数.
    当函数被声明为内联函数之后, 编译器会将其内联展开, 而不是按通常的函数调用机制进行调用.优点:当函数体比较小的时候, 内联该函数可以令目标代码更加高效. 对于存取函数以及其它函数体比较短, 性能关键的函数

  • 义函数时, 参数顺序依次为: 输入参数, 然后是输出参数。
    标准化函数参数顺序可以提高可读性和易维护性

  • 造函数体中进行初始化操作
    如果对象需要进行有意义的 (non-trivial) 初始化, 考虑使用明确的 Init() 方法并 (或) 增加一个成员标记用于指示对象是否已经初始化成功.

  • 单个参数的构造函数使用 C++ 关键字 explicit.
    大部分类并不需要可拷贝, 也不需要一个拷贝构造函数或重载赋值运算符. 不幸的是, 如果你不主动声明它们, 编译器会为你自动生成, 而且是 public 的.可以考虑在类的 private: 中添加拷贝构造函数和赋值操作的空实现, 只有声明, 没有定义. 由于这些空函数声明为 private, 当其他代码试图使用它们的时候, 编译器将报错. 方便起见, 我们可以使用 DISALLOW_COPY_AND_ASSIGN 宏:

1
2
3
4
5
6
7
8
9
10
11
12

#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
class Foo {
public:
Foo(int f);
~Foo();

private:
DISALLOW_COPY_AND_ASSIGN(Foo);
};
  • 仅当只有数据时使用 struct, 其它一概使用 class.

  • 编写简短函数
    如果函数超过 40 行, 可以思索一下能不能在不影响程序结构的前提下对其进行分割.

  • 存取控制

将所有数据成员声明为 private, 并根据需要提供相应的存取函数. 例如, 某个名为 foo_ 的变量, 其取值函数是 foo(). 还可能需要一个赋值函数 set_foo().一般在头文件中把存取函数定义成内联函数.

  • 声明顺序

在类中使用特定的声明顺序: public: 在 private: 之前, 成员函数在数据成员 (变量) 前;

通常是:

  • public -> protected -> private;
  • typedefs 和枚举
  • 常量
  • 构造函数
  • 析构函数
  • 成员函数, 含静态成员函数
  • 数据成员, 含静态数据成员
  • 类型转换

使用 C++ 的类型转换, 如 static_cast<>(). 不要使用 int y = (int)x 或 int y = int(x) 等转换方式;
不要使用 C 风格类型转换. 而应该使用 C++ 风格.

  • 对于迭代器和其他模板对象使用前缀形式 (++i) 的自增, 自减运算符.

不考虑返回值的话, 前置自增 (++i) 通常要比后置自增 (i++) 效率更高. 因为后置自增 (或自减) 需要对表达式的值 i 进行一次拷贝. 如果 i 是迭代器或其他非数值类型, 拷贝的代价是比较大的.

  • 尽可能用 sizeof(varname) 代替 sizeof(type).

在读《C++编程关键路径》的时候,看到有一章讲的很好。于是分享开来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
void swap(int a, int b) {
int tmp;
tmp = a;
a = b;
b = tmp;
}
int get_ini(int a) {
int i = i + a;
return i;
}

char * get_memory0() {
char * p = (char *) malloc(sizeof(char ) * 20);
strcpy(p,"hello world");
return p;
}

char * get_memory1() {
char * p = "hello world";
return p;
}

char * get_memory2() {
char p[] = "hello world";
return p;
}

int main(int argc,char * argv[]){
int x = 4,y = 3;
swap(x,y);
int z = x - y;
printf("z = %d\n",z);//问题1

z = get_ini(z);
printf("z = %d\n",z);//问题2

char * c0 = get_memory0();//问题3
printf("c0 = %s\n",co);

char * c1 = get_memory1();//问题4
printf("c1 = %s\n",c1);

char * c2 = get_memory2();//问题5
printf("c1 = %s\n",c2);
}

问题1:

a,b没有发生交换,所有函数会在程序运行的时候程序栈上分配一块存储区,这块栈的函数存储区随函数开始而开始,随着函数结束而结束,函数结束后, 这块存储区自动释放,以供其他用途,栈的默认大小是1M,swap(int a, int b)是一个参数传值的函数,函数内部的a,b是参数int a 和 int b的局部拷贝,所以a,b实际可以看成局部变量,他们的值由int a ,int b实参复制而来,只在函数内部有效,当函数体内的a,b离开函数作用域时候,a,b变量就销毁了.函数实参值没有发生改变。

问题2:

返回值i是一个局部变量,函数的返回参数怎么可能是局部变量?函数的返回值由传值和传址两种,传值会在返回处生成一个临时对象,
用于存放局部变量i的一份拷贝。临时对象没有名称。虽然i被销毁了,但是他的拷贝仍然存在。并在函数返回处赋值给z.c0 = “hello world”

问题3:

程序运行期间堆的内存一直都在。返回的p是会被销毁,但是在返回处有p的拷贝对象,指向堆的地址。c1 = “hello world”

问题4:

常量存储区:”hello world”在程序运行期间都在

问题5:

p[]不是指针,是一个数组变量,函数返回时左值拷贝只想的是局部变量的p[12]的首地址,当局部数组p[12]离开作用域后会自动销毁,
这时,函数返回的左值,拷贝指向的是一个被销毁的局部变量地址。所以c2 = 未知

过去的一年里,我很刻意在锻炼一些不足的东西,即便如今还是无法和很多我崇拜的朋友那样成熟,但还是深切感受到成长带有一些痛。

大学的我读了计算机。生长环境的原因,到进入大学才真正接触电脑.不夸张的说,我只会开机。从小一直倔强且自觉的人,顿时感觉自己是个loser。但是我还是很努力的去上课,学习,模仿我的同学,那些我看起来很有“天赋”的人,每个独特的个体有不同的经历,就像有些人初中已经在玩Linux, 有的高中玩信息竞赛,真的有无比的羡慕。你可以想象那时候的我就是一个白痴,什么都不懂,所幸的是,我不放弃,于是在努力学习,厚脸皮的取经,跟上老师的步伐。别人花1个小时,好吧,那我就花10个小时。幸运的是我认识到一些很好的同学,他们之间有些人在我心中占有很重的分量。我是一个感恩的人,当我有能力,也会延续这份恩情,给予同样需要帮助的人。就这样我貌似很白痴地拿下了大学的第一个国家奖学金,但是我不开心,因为,我讨厌成为没有安全感,这种安全感是需要我有足够的编程能力来支撑。而那时的我,可能只是个课业任务完成的比较认真的学生。而对于计算机这样一个动手能力极强的学科,我深深觉得还远远不够。说实话很郁闷。我也觉得很奇怪,为什么一个在高中可以担任篮球队长,一个可以面对做口语翻译欣然接受的人会如此沉默寡言。以至于大家误解我太过低调,囧rz,人什么都可以改变的,当你知道你的路在什么地方的时候。

这期间我养成了每天晚上环大学内环慢跑的习惯,这一坚持便是3年。起初的原因是想调节自己的情绪,后来也就成为一种习惯,庆幸的是,我没有像别人一样沉溺于恶习。纵然我相信天道酬勤,也因起步太慢和方法不对,迟迟找不到感觉,焦虑失望的心必然是存在的,跑步帮助我调节。于是我就找我认为厉害的朋友聊天,遗憾的是,站在高处的他们终究只是习惯了自己的思维,没有站在“弱势群体”的角度思考他们的痛。于是,郁闷还在继续,但我没有停下探索与步伐,这期间我还是在企望某个曙光的到临。那种只能意会不可言传的感觉。I hope Change Coming!

大二下的时候和班里的几位同学组了一个团队“叫神马团队”,渐渐接受各种项目的锻炼,是的,聪明的你会发现这是一个契机,我觉得这是开启心智模式的一个序幕。我本着不懂就更要努力的心态,与团队一起在成长,后来我也成了队长。和一些优秀的人在一起能让你更加优秀,的确是的。我开始用了Vim ,学会了GoogleReader ,掌握了各种提高效率的工具(evernote…),开始无尽的折腾,各种系统,各种好玩的技术。也慢慢找到自己想要的方向,我无限迷恋Unix编程艺术。Geek的血液已经开始流淌于我的信仰里。努力变得有方向和满足感了。迷茫也还是有的。

这期间广泛的阅读让我视野大开,CoolShell,Tinyfool,云风的blog,TimYang的后端日志,DBANote….各种我崇拜的人,他们关于技术学习,以及其他相关文章让我流连忘返。这是我希望成为的人。我也开始广泛的接触经典阅读,可以看看我的豆瓣阅读。我发现我找到了那道曙光,这次我继续坚持。大四的时候,我的成绩是2/280,说实话,从大三起我已经开始逃课了,去做各种自己喜欢的事情。我承认还是有很多东西现阶段理解不了,但也会选择性地接受,有机会继续深究,做有心人。是的, 我开始挑战各种各样的技术难题,自信上来了。点滴感悟之中,也就发现了只会技术远远不够。

因为家里某些原因,我放弃保送上海交大,说出来真的需要勇气,我也知道很多人会对我不理解,当我敢于对别人云淡风轻的提起之时,这背后已经是多次失眠哈哈。看来内心需要修炼。我发现和我一起成长的那帮牛逼的高中同学,他们高等学历的身份多多少少让我感受到了压力,但既然选择,那就承担吧.像一个男人一样去面对。现在的我比学生生涯的任何时候都具有强烈的求职欲望和学习能力,我更加知道自己要成为什么样的人。不谦虚的说,我比以前任何时候那个考过全县第一名的我更要强大,心智模式的打开,在我看来才是教育最重要的目的,让我看到了思维的转变。很可悲的是还是有很多人没有找到这样的意识。感谢读计算机这专业以及一路上遇到的人,让我追求独立思考的精神。

今天听了tiny4voice的一篇文章《如何自学和成长》,我发现有很强劲的共鸣。是的,人不应该限制自己,勇敢的去挑战各种可能。就像我曾经去摆地摊:) 我也慢慢发现如果以后有机会,一定要对那些后来人更加地友善,正如曾经帮助过我的人,生活中,有的人,认为他们已经懂的东西很习以为常,然后以站着说话不腰疼的感受,于是说出来的话就很打击这些很渴望进步的学习者的内心,直至现在,我一直被这样的人伤害过,还好我懂得如何提炼更有效的信息,自我判断,只是当你有一天也走到了他们的位置,对他们态度好一些,但如果能感性点会更好。同理心可以让这个如此残酷的世界变得有那么一点人情味。

我希望接下来的日子里,与我的朋友们一起共勉,每一个看我博客的人,我知道你们会是谁,你们真的很棒,感恩与你们同在,无论怎样,开心是最佳选择 :-) 。听到一句话很想与大家分享

岂能尽如人意,但求无愧于心,让我们把所有的不好叫做经历。

python的创建多线程的方法

使用线程有两种模式:

  • 一种是创建线程要执行的函数,把这个函数传递进Thread对象里,让它来执行;
  • 一种是直接从Thread继承,创建一个新的class,把线程执行的代码放到这个新的 class里。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import string, threading, time

def thread_main(a):
global count, mutex
# 获得线程名
threadname = threading.currentThread().getName()

for x in xrange(0, int(a)):
# 取得锁
mutex.acquire()
count = count + 1
# 释放锁
mutex.release()
print threadname, x, count
time.sleep(1)

def main(num):
global count, mutex
threads = []

count = 1
# 创建一个锁
mutex = threading.Lock()
# 先创建线程对象
for x in xrange(0, num):
threads.append(threading.Thread(target=thread_main, args=(10,)))
# 启动所有线程
for t in threads:
t.start()
# 主线程中等待所有子线程退出
for t in threads:
t.join()
if __name__ == '__main__':
num = 4
# 创建4个线程
main(4)

方法二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import threading
import time

class Test(threading.Thread):
def __init__(self, num):
threading.Thread.__init__(self)
self._run_num = num

def run(self):
global count, mutex
threadname = threading.currentThread().getName()

for x in xrange(0, int(self._run_num)):
mutex.acquire()
count = count + 1
mutex.release()
print threadname, x, count
time.sleep(1)

if __name__ == '__main__':
global count, mutex
threads = []
num = 4
count = 1
# 创建锁
mutex = threading.Lock()
# 创建线程对象
for x in xrange(0, num):
threads.append(Test(10))
# 启动线程
for t in threads:
t.start()
# 等待子线程结束
for t in threads:
t.join()

队列同步

Python的Queue模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue。这些队列都实现了锁原语,能够在多线程中直接使用。可以使用队列来实现线程间的同步

线程池原理:

我们把任务放进队列中去,然后开N个线程,每个线程都去队列中取一个任务,执行完了之后告诉系统说我执行完了,然后接着去队列中取下一个任务,直至队列中所有任务取空,退出线程.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import time
import threading
import Queue

class Worker(threading.Thread):
def __init__(self, name, queue):
threading.Thread.__init__(self)
self.queue = queue
self.start()
def run(self):
# 著名的死循环,保证接着跑下一个任务
while True:
# 队列为空则退出线程
if self.queue.empty():
break
# 获取一个项目
foo = self.queue.get()
# 延时1S模拟你要做的事情
time.sleep(1)
print self.getName(),':', foo
# 告诉系统说任务完成
self.queue.task_done()

queue = Queue.Queue()

# 加入100个任务队列
for i in range(100):
queue.put(i)

# 开10个线程
for i in range(10):
threadName = 'Thread' + str(i)
Worker(threadName, queue)
# 所有线程执行完毕后关闭
queue.join()
0%