前两天工作需求,把python脚本从crontab的方式改成守护进程(daemon),上线后发现,内存飙升,cpu飙高,程序直接死掉,让我伤心欲绝,郁郁寡欢,终日不得眠啊。开始以为是内存溢出用gc调试好久也看不出问题。由于项目使用了Django-ORM,所以开始怀疑是不是因为Django引发的性能问题。

搜索了一下关于django内存泄露的文章,这片文章 —— Django"内存泄漏"的问题 给我了启示:

文中第一条就提到:Make sure that you set DEBUG to False in settings.py,在DEBUG模式下,所有的SQL查询都会被保存在内存中.我顿时想起,由于我整个项目还在调试阶段,这个DEBUG变量是设置为True的

DEBUG设置为False后,内存泄漏的问题就不复存在了

可我整个项目还需要调试,不能就这么简单的关闭DEBUG模式,怎么办? 我一开始想在后台模块import settings后再重新设置DEBUG变量

下面分析一下脚本程序,import了Django的models,并且对数据库的数据做了轮询操作,所以执行大量的sql去读数据库的全部数据,由于线上DEBUG改成了True,所有的SQL查询保存在了内存中,这样导致内存飙高,好吧不得不说为了把脚本弄成守护进程方式,还用了个while True的死循环,虽然改成了while 1,但是心里还是怪怪的。

找到问题的原因,我就把DEBUG改成False重启一下,果然内存不再飙高,就此搞定。在此记录一下,解决线上问题的一个小思路。

有时候,在Django的model中,直接查询出来的orm对象,想直接转成json会报错:

1
TypeError is not JSON serializable
1
2
3
4
5
6
7
8
def convert_to_builtin_type(obj):
# print 'default(', repr(obj), ')'
# Convert objects to a dictionary of btheir representation
d = { '__class__':obj.__class__.__name__,
'__module__':obj.__module__,
}
d.update(obj.__dict__)
return d

然后在函数中调用:

1
2
3
ip = Ip.objects.filter(ip=ip)
context = {'ip': list(ip)}
return HttpResponse(json.dumps(context, ensure_ascii=False, indent=4, default=convert_to_builtin_type))

如上先filter出ip=ip的条目保存在ip变量中,然后格式化下保存在context变量中。调用时放在default中。

如果喜欢pythonic,可以用下面lambda方式搞定:

1
return HttpResponse(json.dumps(context, ensure_ascii=False, indent=4, default=lambda o: o.__dict__))

今天同事问我一个python面试题,关于python跳出多层循环,原来还真没用过,网上一查还真有点意思,下面记录一下:

Python 本身没有“break n” 和“goto” 的语法,这也造成了Python 难以跳出多层(特定层数)循环。下面是几个跳出多层(特定层数)循环的tip。

1、自定义异常

1
2
3
4
5
6
7
8
9
10
11
12
class getoutofloop(Exception): pass

try:
for i in range(5):
for j in range(5):
for k in range(5):
if i == j == k == 3:
raise getoutofloop()
else:
print i, '----', j, '----', k
except getoutofloop:
pass

2、封装为函数return

1
2
3
4
5
6
7
8
9
def test():
for i in range(5):
for j in range(5):
for k in range(5):
if i == j == k == 3:
return
else:
print i, '----', j, '----', k
test()

3、for … else … 用法

上面的两种都是只能跳出多层而不能跳出特定层数的循环,接下来的这个正是为了跳出特定层数的循环。

1
2
3
4
5
6
7
8
9
10
11
for i in range(5):
for j in range(5):
for k in range(5):
if i == j == k == 3:
break
else:
print i, '----', j, '----', k
else: continue
break
else: continue
break

else在 while和for 正常循环完成之后执行,和直接写在 while和for 之后没有区别,但是如果用break结束循环之后else就不会执行了。这也是个很新奇的做法。

才知道原来可以作为跳出多层循环用。不过要是有多次跳出不同层的循环的需求,也没辙了。

python is是种很特殊的语法,你在其它的语言应该不会见到这样的用法.
python is主要是判断2个变量是否引用的是同一个对象,如果是的话,则返回True,否则返回False

比如:

1
2
a = 'abc'
b = 'abc'

a is b 返回True,因为变量a和b都存储了字符串’abc’对象的地址。

如果是:

1
2
a = 'abc'
c = 'abcd'

print a is c 返回False,因为变量a和c存储了字符串对象地址不一致。

看了Django的官方文档,关于model这有介绍Multiple databases,但是没有介绍超过两个数据库的连接情况,这里我用mysql举例子,连接3个mysql数据库。估计这么用的不多哈哈哈,我们的需求比较复杂两个mysql上的都是公用数据,然后默认的数据库是我项目使用的数据库,保存着自己项目的账户系统和使用的一些信息。

settings.py

下面是settings文件的配置,添加三个数据库,default为本项目自己的数据库,剩下两个为外部数据库

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
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'my_db',
'USER': 'root',
'PASSWORD': '123456',
'HOST': '127.0.0.1',
'PORT': '3306',
},
'web_db': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'web_db',
'USER': 'root',
'PASSWORD': '123456',
'HOST': '127.0.0.1',
'PORT': '3306',
},
'admin_db': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'admin_db',
'USER': 'root',
'PASSWORD': '123456',
'HOST': '127.0.0.1',
'PORT': '3306',
},

}

router

根据官方文档提示需要自己写个router文件,我的修改如下:

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
class AuthRouter(object):
""" 控制 adminapp 应用中模型的
所有数据库操作的路由 """


def db_for_read(self, model, **hints):
if model._meta.app_label == 'adminapp':
return 'admin_db'
elif model._meta.app_label == 'webapp':
return 'web_db'
return None

def db_for_write(self, model, **hints):
if model._meta.app_label == 'adminapp':
return 'admin_db'
elif model._meta.app_label == 'qingsong':
return 'web_db'
return None

def allow_relation(self, obj1, obj2, **hints):
if obj1._meta.app_label == 'adminapp' or obj2._meta.app_label == 'adminapp':
return True
elif obj1._meta.app_label == 'qingsong' or obj2._meta.app_label == 'qingsong':
return True
return None

def allow_syncdb(self, db, model):
#django1.7
print "db:%s,model:%s"%(db,model)
print model._meta.app_label
if db == 'admin_db':
return model._meta.app_label == 'adminapp'
elif model._meta.app_label == 'adminapp':
return False
if db == 'qingsong_db':
return model._meta.app_label == 'qingsong'
elif model._meta.app_label == 'qingsong':
return False
return None

def allow_migrate(self, db, model):
#django1.7
if db == 'admin_db':
return model._meta.app_label == 'adminapp'
elif model._meta.app_label == 'adminapp':
return False
return None

然后根据官方文档在settings中加入:

1
DATABASE_ROUTERS = ['path.to.AuthRouter', 'path.to.PrimaryReplicaRouter']

model中的使用

关于app_label在1.6和1.7中使用稍有不同,官方文档有详细记载,这里我举例Django1.6的方式:

在model中加入app_label标签,这个model属于哪个数据库,写上数据库的名字(settings.py文件中的名字),例如:

1
2
3
4
5
6
7
8
class Test(models.Model):
name=models.CharField(max_length=30, unique=True)
class Meta:
db_table = 'test'
app_label = 'adminapp'

def __unicode__(self):
return self.name

今天,谈谈工作,谈谈技术,谈谈理想,谈谈人生

工作

最近,又换了份工作,其实本来是不想走的,但是由于自己太浮躁,换了部门,导致自己没活干,天天混日子也不是我的性格,所以最终确定还是找个靠谱的python业务开发。离职当天,我就高烧39°,战胜病魔后,我痛定思痛,总结了很多,在这里跟大家分享一下。

首先,自己好胜心太强,以至于太急躁,没活干的时候总是胡思乱想,导致了自己换部门,以后在没活干的时候正好是自己积累和学习的过程是个很难得的机会,要好好把握。所以不管干什么要谋定而后动。

其次,要找到自己工作的目标,有了目标就不会胡乱去想。

最后,把目标转化成自己要学的技术,比如我要学的技术就是linux和c,相关的书籍《unix环境编程》《unix网络编程》《unix编程艺术》《c语言程序设计》

关于python开发实践视频

1 初识Python:人人都爱列表

2 共享你的代码:函数模块

3 文件与异常:处理错误

4 持久存储:数据保存到文件

5 推导数据:处理数据!

6 定制数据对象:打包代码与数据

6课,一共12课时,我答应大家的一定会去录制,最近灿哥正好组织培训分享,我也会加入进去。2个多月没更新视频,一是自己这段时间总是在考虑工作的事,二是在想用什么更好的方式传播分享知识,其实文字是最好的方式,但是文字有时候又不太好表达,自己的文字功底还没练到家。所以我也会尝试的去做一做,基础课程录制完成,稍微的写下gitbook。当做日后实战的教材也好。基础的课程我就不在写太多文字的东西了,因为我是以head first python 为基础录制的,希望大家可以支持他们一下。

这几年一直在琢磨培训学习的事,也是业余培训讲师,随着年岁的增长如果自己发现了更好的学习方法和方式,也会再跟大家分享,弄不好会自己写一本编程的基础书籍。

没啥难的看我的节奏:

使用Shift + command + P调出命令面板:

输入 install 调出 Package Control: Install Package 选项,按下回车

在列表中分别找到 CoffeeScript,compass,sass和sass build按下回车进行安装

重启Sublime Text 2使之生效

共享你的代码

共享你的代码课程知识点:

  • 编辑器
  • 注释
  • 命名空间
  • PyPi
  • 上传

上传PyPi没有成功,因为nester这个模块名已经有了,大家可以更改下名字,再上传测试,这个作为作业。

测试完成 你就可以使用如下命令安装:

1
pip install nester  #nester为你自己的模块名

关于编辑器 可以看 配置sublime打造python编辑器 先可以有了自己的需求感觉不方便可参考配置。

最近项目传到服务器上测试,由于没开启log,有些错误没法判断,顾设置之,有此博文。

修改settings文件,添加如下代码:

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
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
},
'simple': {
'format': '%(levelname)s %(message)s'
},
},
'handlers': {
'null': {
'level': 'DEBUG',
'class': 'logging.NullHandler',
},
'console':{
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
# 'filters': ['special']
}
},
'loggers': {
'django': {
'handlers': ['console'],
'propagate': True,
'level': 'ERROR',
},
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True,
},
}
}