Archive for python

写的dht协议搜索的程序,这几天优化了一下发现速度确实快了好多。但是出现了一个新的问题,内存直接飙升,我开了十个爬虫占用内存800m。开始我以为是节点太多了,找了几个小问题修改一下,发现没用。后来就到网上查找python内存分析的工具,查了一点资料发现python有个meliae库操作非常方便,就使用分析了一下,发现不是节点太多的原因0 0,是保存发送的t_id,用来标示返回的消息是那个发出的一个字典过大了。 从分析的结果非常容易的定位了某个对象的数量和大小,非常容易分析。我开始以为是因为好多发送查询信息以后,对面没返回造成这个字典里的元素没有释放造成的,我就用过期时间判断了一下,进行过期删除。发现是小了,但是不是非常显著,好像少了几十不到100M。后来又减少了查找一个随机hash的时间,以前是1分钟查一次,我改成了就第一次查!,发现没减少0 0.不知道是啥的原因。应该就是查找hash,询问节点,然后返回然后询问里边的节点,最后数量越来越多,但是我不明白的是,怎么会这么多运行一分钟就有60万条。也就是说当时内存没释放的对象就有这么多。达到这个内存占用后,基本就不再变化,有很小很慢的提升,因为还开的其他程序,不确定是不是这些程序其他对象的增加造成的。等分阶段dump测试一下。 安装直接pip install meliae 就ok了,我看好久没更新的项目了,不知道还有没有好的替代品不过用着还不错。 将内存dump到文件

	from meliae import scanner
	scanner.dump_all_objects('/tmp/dump%s.txt' % time.time())
分析文件:
	from meliae import loader
	#加载dump文件
	om = loader.load('/opt/log/dump.txt')
	#计算各Objects的引用关系
	om.compute_parents()
	#去掉各对象Instance的_dict_属性
	om.collapse_instance_dicts()
	#分析内存占用情况
	om.summarize()
字段意义如下: Index : 行索引号 Count : 该类型的对象总数 %(Count) : 该类型的对象总数 占 所有类型的对象总数 的百分比 Size : 该类型的对象总字节数 %(Size) : 该类型的对象总字节数 占 所有类型的对象总字节数 的百分比 Cum : 累积行索引后的%(Size) Max : 该类型的对象中,最大者的字节数 Kind : 类型 分析某个对象,找出它的引用关系
	#得到所有的POP3ClientProtocol对象
	p = om.get_all('POP3ClientProtocol')
	#查看第一个对象
	p[0]
	#可以查看该对象的所有引用
	p[0].c
	#查看谁引用了这个对象
	p[0].p

Continue

今天在网上看到type的一段代码 ,然后查了一下文档,才知道type还有三个参数的用法。 http://docs.python.org/2/library/functions.html#type 以前只是知道type可以检测对象类型。然后发现了一个有趣的用法。 def println(self): a = 1 + 1 print "%s,%s" % (self.aa, a) A = type('A',(),{'aa':'print a', 'println': println}) a = A() type(a) Out[11]: __main__.A a.println() print a,2 第一个参数是类的名字,第二个元组是父类,第三个是属性。 哈哈,我觉得很好笑,虽然我函数里边第一个参数还是写的self,但是如果写一段代码都用这种方法定义类,然后再不注意类名的规范,代码会变的很难读。

Continue

从看了小虾的博文以后就也想写一个爬虫,一直写到现在才有点眉目。。其中还参考了http://codemacro.com上写的思路,不过有很多功能还没涉及到。 已经实现的功能,创建一个节点,能在dht网络中友好的生存并获取info_hash,好多技巧还没用到。实现插入数据库中,现在直接访问django写的应用(主要也是测试功能,两个功能分开了还没合到一起,直接用django的orm肯定要快好多),然后我在django里边写了下载种子文件和解析种子文件信息的功能。发现有许多hash找不到种子,下载不下来,后面还要在看一下怎么生成种子文件。分析种子信息的代码是从网上找的,然后修改了一下。 一个节点可能有点偏,不计算重复,开始时平均一分钟2个,计算重复一份钟一个。 前段时间又想到以前看群里讨论的关于p2p的应用,想自己实现一下,正好现在对协议了解了。不准备用 python写了,再看一个新语言折腾一下。

Continue

1.按照zeromq。下载地址:http://download.zeromq.org/ 官方文档 http://zeromq.org/area:download#toc4 2.安装pyzmq。easy_install pyzmq   不错的例子:https://learning-0mq-with-pyzmq.readthedocs.org/en/latest/index.html   我用的pair-pair模式,虽然我只要单向传递消息,这种模式不会产生消息丢失。我开始使用pub-sub模式,发现不知道什么原因,第一个消息总会丢失。。。这种模式是最快的,然后决定不使用了。但是使用pair模式存在的问题是,如果接收端的服务没启动,就会阻塞在那里,会产生timeout。

Continue

执行系统命令一般都是os.system(),但是我想返回编译c语言程序的结果,找到一个os.popen()发现不行,又找到一个commands.getoutput成功解决了。 官方文档: http://docs.python.org/2/library/subprocess.html#module-subprocess

Continue

参考资料: http://eshlox.net/en/2012/09/11/nginx-uwsgi-virtualenv-and-django-ubuntu-1204/ https://virtualenv-chinese-docs.readthedocs.org/en/latest/ https://uwsgi.readthedocs.org/en/latest/tutorials/Django_and_nginx.html http://www.virtualenv.org/en/latest/ 在virtualenv环境下安装 mysqldb的时候遇到几个问题 $ sudo apt-get install libmysqlclient-dev $ sudo apt-get install python-dev   把第一个链接的文章转过来,防止以后不能访问,其他几个都是官方文档,主要还是参考官方文档。 First install required applications.

sudo apt-get install nginx uwsgi uwsgi-plugin-python python-virtualenv
Versions of packages that will be used:
Nginx 1.1.19.1
Uwsgi 1.0.3+dfsg-1ubuntu0.1
Virtualenv 1.7.1.2-1
Django 1.4.1
Virtualenv. I store my project in ~/projects. Now I'm creating python virtual environment for my project and I'm installing Django.
cd ~/projects/
virtualenv eshlox.net
cd eshlox.net
source bin/activate
pip install django
django-admin.py startproject project
Nginx configuration. IMHO, by default, nginx is configured for basic tasks. I won't change this configuration in this entry. Configuration files are stored in /etc/nginx/sites-available. Go to this directory and create a new file.
cd /etc/nginx/sites-available
vim eshlox.net
It's example configuration.
server {
    listen  80;
    server_name eshlox.net www.eshlox.net;
    access_log /var/log/nginx/eshlox.net_access.log;
    error_log /var/log/nginx/eshlox.net_error.log;

    location / {
        uwsgi_pass  unix:///tmp/eshlox.net.sock;
        include     uwsgi_params;
    }

    location /media/  {
        alias /home/eshlox/projects/eshlox.net/project/project/media/;
    }

    location  /static/ {
        alias  /home/eshlox/projects/eshlox.net/project/project/static/;
    }
}
We must create symlink to enable this.
cd /etc/nginx/sites-enabled
ln -s ../sites-available/eshlox.net .
Uwsgi. Like with Nginx.. configuration files are stored in /etc/uwsgi/apps-available. Go to this directory and create a new file.
cd /etc/uwsgi/apps-available
vim eshlox.net.ini
[uwsgi]
vhost = true
plugins = python
socket = /tmp/eshlox.net.sock
master = true
enable-threads = true
processes = 2
wsgi-file = /home/eshlox/projects/eshlox.net/project/project/wsgi.py
virtualenv = /home/eshlox/projects/eshlox.net
chdir = /home/eshlox/projects/eshlox.net/project
touch-reload = /home/eshlox/projects/eshlox.net/project/reload
Enable this.
cd /etc/uwsgi/apps-enabled/
ln -s ../apps-available/eshlox.net.ini .
That's all. Now, run this services.
sudo service nginx start
sudo service uwsgi start
Of course, this is a very basic configuration. Change it according to your needs.

Continue

下载了tornado 0.1的代码进行学习,之所以选择tornado,是看网上对非阻塞模式评价很高,他也不仅仅是web框架,而且相对django来说代码少多了(django的代码也有看)。选择0.1的原因还是代码相对简单,差别也不大。 查看demos里的helloworld,代码如下:

import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
import logging

from tornado.options import define, options

define("port", default=8888, help="run on the given port", type=int)

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

def main():
    tornado.options.parse_command_line()
    application = tornado.web.Application([
        (r"/", MainHandler),
    ])
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()

if __name__ == "__main__":
    main()
从options倒入options和define。先看看官方的描述: 命令行解析模块,来定义使用参数。 例如:上边代码中define("port", default=8888, help="run on the given port", type=int)这句,当年在终端输入helloworld.py --help的时候,将会有“--port                           run on the given port (default 8888)”的提示。 tornado.options.parse_command_line()这一行是对命令行进行解析,格式:("--myoption=myvalue")。也可以是配置文件解析tornado.options.parse_config_file("/etc/server.conf"),配置文件必须是python文件,像: myoption = "myvalue" myotheroption = "myothervalue" 参数指定类型type可以是:datetimes, timedeltas, ints, and floats。 主要说_Options()和_Option() 344行实例化了类_Options,options = _Options.instance(),options现在为空字典,以后将 存储所有选项,通过上边提到的三种方式,添加是只通过define()。 _Option的参数来自define,metavar选择类型的参数,multiple=True会解析多个值,结果列表保存。 这个类里有个有parse()方法,学到很多知识。主要用于解析命令行下的参数,需要将选项对应的类型进行转换,作者使用_parse={type:parse_option_func}.get(type,type)的方法,然后通过_parse(value)进行解析转换参数。没有定义过的解析方法就直接使用type(value)转换了,只能说作者好强大。 代码的最后定义了几个默认设置。0.1的里面有help和logging。 对于options模块里的log代码等下一次总结,剩下的几个函数就很简单了,就不记录了。

Continue

由于Google reader的关闭,这段时间接触rss的东西相对多很多。试过qq的reader,不怎么样,阅读速度没有,是否阅读的标记也没有。其他网站的不想用,又要多注册账户。 找到python的rss处理包feedparser,官方文档很详细。http://pythonhosted.org/feedparser/ >>> import feedparser >>> d = feedparser.parse('http://0x55aa.sinaapp.com/feed') >>> a = d.feed >>> a.title 可以使用keys来查看字典键,可以很清楚的弄懂每一个的意思。官方文档上每一个都有介绍。 >>> d['feed'].keys() rss订阅的文章在d.entries里面是一个列表。 详细使用和高级用法见feedparser官方文档。

Continue

正在编写的程序用的很多Windows下的操作,查了很多资料。看到剪切板的操作时,想起以前想要做的一个小程序,当时也没做,现在正好顺手写完。 功能:按printscreen键进行截图的时候,数据保存在剪切板里面,很不方便。比如游戏的时候截一个瞬间的图片,但你不能退出游戏保存图片,不方便多次截图。而我也不喜欢安装各种软件,所以准备写这个工具。 思路:一个是自定义快捷键,截图,保存。考虑到很可能各种冲突,取消。然后还是用按printscreen来截图,然后从剪切板读取图片数据,保存。想法是,先监听键盘按键,当printscreen按键时,读取剪切板内容,最后保存图片到指定位置。 1 监听键盘按键:从网上找到资料,安装pywin32,pyhook。链接:http://sourceforge.net/projects/pyhook/,http://sourceforge.net/projects/pywin32/。教程:http://sourceforge.net/apps/mediawiki/pyhook/index.php?title=PyHook_Tutorial。 2 读取剪切板内容,也是需要pywin32.文档在:[Pythonpath]\Lib\site-packages\PyWin32.chm,在线的:http://timgolden.me.uk/pywin32-docs/index.html 文档中给出的几种格式都不是图片保存的数据,Google搜索“Standard Clipboard Formats”,链接:http://msdn.microsoft.com/en-us/library/windows/desktop/ff729168%28v=vs.85%29.aspx,所有的格式,主要就是1-17. 好在文档中有一个函数:GetPriorityClipboardFormat,可以返回剪切板中的格式,从一个迭代器中。于是手动输入找到了,y有时为6,win32con.CF_TIFF,还会为2。当然这里直接用返回数据就行了,不需要知道是什么。 主要用到: OpenClipboard,CloseClipboard,GetPriorityClipboardFormat,GetClipboardData,这几个函数文档都有介绍,主要说说CloseClipboard,官方文档上讲,不要在剪切板里放置对象后调用CloseClipboard。 3 保存图片: 到这里发现可以直接用PIL模块,直接解决问题,上面太曲折T_T。 可以直接使用ImageGrab.grab() 进行抓屏,或者使用ImageGrab.grabclipboard()从剪切板获取图像。   最后变成,监听按键,按下printscreen后,用pil截图保存。T_T 感觉还不如设置快捷键,这样应该少占用内存。 cut.py

Continue

PyStringObject需要保存字符串长度(ob_size),当产生字符串对象后,将不会改变(不可变对象)。这一特性使得PyStringObject对象可作为dict的键值,同时也使一些字符串操作的效率大大降低了,比如字符串连接操作。   typedef struct { PyObject_VAR_HEAD long ob_shash; int ob_sstate; char ob_sval[1]; } PyStringObject;   同c语言一样,字符串末尾以‘\0’结尾,但是中间可以出现’\0’,ob_sval指向一段长度为ob_size+1个字节的内存,字符串结束需要满足ob_sval[ob_size] == ‘\0’   Ob_hash缓存该对象的hash值,初始值为-1。Ob_sstate在书后面介绍intern机制,对于被intern之后的字符串,在整个python运行期间,系统中都只有唯一一个与该字符串对应的PyStringObject对象。当判断两个PyStringObject对象是否相同时,如果都被intern了,只要检查对应的对象是否相同即可。   PyStringObject对应的类型对象为PyString_Type,tp_itemsize被设置成sizeof(char),即一个字节。与ob_size共同决定申请多少内存。 字符串对象有长度限制,大小为2GB。   Intern机制对相同字符串的处理: a = “python” b=”python” print a,b   intern机制的关键,是有一个叫interned的字典,记录intern机制处理过的PyStringObject对象。 对于上面的例子,先创建PyStringObject对象a,先会检查interned字典里有没有字符串与a相同,这里显然没有,将会添加到interned字典里。当创建b后(必须先要创建)执行intern操作,继续检查interned字典,发现有相同的字符串对象a,然后指向b的PyObject指针将指向a,b的引用计数减1,b将会被回收了。   有长度为256的字符缓冲池,添加到缓冲池的流程:当在创建PyStringObject对象时(还没创建),先检查长度。为字符时,再检查字符缓冲池是否有该字符,有,直接返回缓冲的该对象,结束;没有,创建PyStringObject对象,检查长度为字符,对对象进行intern操作,最后缓存至字符缓冲区。创建StringObject的两个函数不是太长也有注释,还能看懂。   字符串连接 通过”+”操作符对字符串进行连接是,调用string_concat函数:先计算连接后的字符串的长度,然后创建新的字符串对象分配给他计算的长度内存,最后复制。 Join操作,调用函数string_join:基本流程和“+”操作符相同。这里的区别是,“+”操作符有两个字符串就要创建一个新对象,join是对列表中的所有字符串进行,只要创建一次新对象就行。当进行多个字符串的连接时,应使用join操作。  

Continue