什么是异常,其实我不是很清楚

2014年1月17日 17:24

起因

平时能较好的处理异常。但在自定义异常时才发现,并不了解异常。对于用的api也不真明白为什么要抛出异常,而不用其它方式。
 
针对自己的疑惑,觉得有必要好好思考下
 

异常机制的产生

语言发展是从汇编到C再到C++. 在汇编和C语言中都没有异常机制。
它们用的是错误编码机制. 直到C++才出现异常机制。
 
什么导致C++中出现异常机制?要回答它,需先了解错误编码机制的存在的缺点。
* 错误信息不全
调用信息不全; 错误种类很多,返回会过于简单.
* 默认可以被忽略
默认可以不用检查返回的错误编码,很容易使程序处在不正常状态.
* 不能跨作用域传送
只能一层层的向上传送,每层都有一堆检查错误的代码,会掩盖正常处理。
 
编码机制是为解决程序错误这个需求而生。在错误发生时最重要的是:
错误内容是什么?
在哪儿出错了?
为什么出错?
编码机制存在着缺点,不能很好解决这几个需求。
 
异常机制能完善的解决了这些问题. 所以后来语言中都加入了异常机制。
 
异常机制也就了两个重要特点:
* 沿着调用堆栈向上传递错误
* 不可忽略
前者可获得完整的调用信息,方便定位错误地点. 也可将错误处理代码分离出来。
后者明确拒绝不健康运行状态,是程序正确性的关键。
 

对异常的疑惑

一个简单的python异常
>>> a = {"a": 1, "b": 2}
>>> a.pop(c)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'c' is not defined
对于它我有很多疑问:
1. 为什么抛异常?返回特殊标记不行吗.
2. 什么是异常?为什么它会被定义为异常.
 
回答第一个问题
异常的特点是就是"不可忽略",上面的pop没有任何值适合作为标记,它只能抛异常. 如果忽略了,可能会让程序处在不健康状态。
 
回答第二个问题
异常是判断词,与它对的应是正常。
那么什么是正常?回答它也就可回答第二个问题了.
异常与正常其实隐藏着一个判断, 隐藏着一个判断标准。
 
那么谁在判断,谁在制定标准。答案是你。
你在决定什么是异常,什么时候该抛异常,抛什么类型的异常。
例子中就是python作者在背后做了思考/定义,决定它应该作为异常。
 

如何使用异常

当定义好什么是正常,知道哪些是不正常而且不可忽略时,就是使用异常的时候。为防止不健康运行状态. 而且不可忽略.
 
值得注意的是:通常是没法考虑全面的,会有漏掉的情况,应以保守的方法处理,对未考虑到的情况全部作为异常处理,再分辨,逐步完善。
 
异常的重要性
它是软件好坏的重要标志,任何在这上面处理不好的软件,无不是充满了坑。
 

Tags: 异常
评论(2) 阅读(1088)

在用proxychains时, ping用不了怎么办

2014年1月16日 10:49

一般用ping来测试网络是否连通. 在用proxychains代理时,发现ping用不了
[wyq@localhost ~]$ proxychains ping 135.32.9.98
ProxyChains-3.1 (http://proxychains.sf.net)
ERROR: ld.so: object 'libproxychains.so.3' from LD_PRELOAD cannot be preloaded: ignored.
PING 135.32.9.98 (135.32.9.98) 56(84) bytes of data.
proxychains支持的是socks,http, https协议.它们以tcp或者udp协议为基础. 所以proxychains只支持使用tcp或udp协议的程序. ping用的是ICMP协议,不以tcp或udp为基础,所以用不了。
 
有其它办法吗?
以tcp或udp为基础,测试网络是否可用的工具,比较好用的有wget
[wyq@localhost ~]$ proxychains wget 135.32.9.98
ProxyChains-3.1 (http://proxychains.sf.net)
--2014-01-16 09:44:57--  http://135.32.9.98/
正在连接 135.32.9.98:80... |S-chain|-<>-192.168.1.115:1080-<><>-135.32.9.98:80-<--denied
失败:拒绝连接。
虽然提示拒绝连接,但是输出信息,已能说明网络连通了.
 
wget本身简单易用,在这种情况下,用来测试网络是否可用,还是比较适合的。
 

评论(0) 阅读(1608)

内网到外网的隧道

2014年1月15日 23:22

今天需要在内网机器上安装一个包,而且没有与系统版本匹配的rpm. 所以只能自己编译安装。编译时出现错误,原因是系统没有安装gcc. 只好再安装gcc,然而再次出现问题,发现缺少gcc的依赖了,而且是一堆的依赖包. 没有办法,只能再一个个安装依赖包. 相信手动安装过linux软件的人,能够深深体会到相互依赖问题会让人有多痛苦。 好不容找到这些特定版本的包,最后出现悲剧了,貌似其中几个依赖包,由版本比较老,网上已经没有了。而且由于内核版本的原因,gcc也只能安装这个版本的。
 
结果出现了安装某个包,需要gcc,安装gcc,需要依赖包,部分依赖包找不到。并且内核限制了只能安装这个版本的gcc。并且系统的安装盘是精简版的,没有常用软件的安装包.
 
找依赖包已经让人很痛苦了,结果是这样,让人很恼火. 下定决心要在内网机器上使用yum,用它来解决这个问题。
为达到这个目的,需要在内网和外网间搭一条隧道,让内网能访问外网。
 
工作的网络环境
工作是在外网,系统在独立的内部网络。在外网访问内网需要通过专门的vpn软件。
这个vpn软件,只能运行在windows下,使外网机器拥有临时的内网地址,运行时外网机器不能访问外网。
 
其中网内到外网的端口转发
proxychains ssh  -N -D 1090 wyq@192.168.1.102
 
这里面最要的不是怎么建数据通道,而是怎么绕过这个特定的vpn软件.
工作原因实现方法只能略说.
 
 
 

Tags: ssh proxychains
评论(0) 阅读(648)

objgraph无法生成分析图的原因

2014年1月14日 13:23

objgraph 是用于诊断内存问题的有用的工具 

安装objgraph

 

sudo pip install objgraph

用小段测试代码,生成png格式的分析图片

#encoding=utf-8
import objgraph


def main(hi):
    print hi

if __name__ == '__main__':
    hi = 'hi'
    main(hi)
    objgraph.show_backrefs([hi], filename='/tmp/hi.png')

会出现错误

Graph written to /tmp/objgraph-Nieb4E.dot (6 nodes)
Graph viewer (xdot) and image renderer (dot) not found, not doing anyt
hing else   

原因: 缺少依赖包

sudo yum install python-xdot  perl-Image-Dot

 

 

 

 

评论(3) 阅读(2738)

yum查找多个词

2014年1月14日 11:28

yum search不支持多个关键词,可以用grep

sudo yum search xdot |grep viewer

 

评论(0) 阅读(544)

fedora20远程桌面

2014年1月13日 16:05

通过代理远程登陆其它网段的机器,要以命令行方式启动远程桌面. 

在fedora20以前,启动远程桌面的命令是rdesktop。目前的fedora20中未提供rdesktop,需要自己安装

[wyq@localhost workspace]$ sudo yum install rdesktop

或者使用vinagre命令启动

[wyq@localhost workspace]$ vinagre

评论(0) 阅读(1294)

webpy+DBUtils是如何将数据库连接数占满的

2014年1月10日 11:41

webpy简单易用,而且非常轻量。这些特点很容易让人忽略它作为web服务器的主要目标,而把它当作一个小模块使用。
现在就把它当作小模块,只使用它操作数据库的api.
 
下面是个小程序,目的就是访问数据库,然后关闭连接。
import web

def main():
    db = web.database(port=5432, host='localhost', dbn='postgres', db='tax',
                      user='postgres', pw='postgres')
    rs = db.query("select count(*) as count from pg_stat_activity")
    print list(rs)[0].count
    db.ctx.db.close()

if __name__ == '__main__':
    main()
在正常情况下,上面程序表现很正常。不会有任何问题.
 
如果变成周期程序,并且安装了DBUtils模块
import time
import web
import psycopg2

def main():
    db = web.database(port=5432, host='localhost', dbn='postgres', db='tax',
                      user='postgres', pw='postgres')
    rs = db.query("select count(*) as count from pg_stat_activity")
    print list(rs)[0].count
    db.ctx.db.close()

if __name__ == '__main__':
    while True:
        main()
        time.sleep(1)
输出的count值不断增加,最终将连接数占满。
 
为什么close没有效果,数据库连接数不断增加?
 
第一个问题:close关闭的是什么?
在有DBUitls时,close关闭时的PooledDB.connection()产生的连接.
在无DBUtils时,close关闭的时psycopg2.connect()产生的连接.
 
第二个问题: 在有DBUtils时close为什么不会减少连接数?
写了段代码,来看看close是怎么回事
import psycopg2
from DBUtils import PooledDB

def main():
    #mincached,maxconnections限制连接池中的连接数
    pool = PooledDB.PooledDB(psycopg2, port=5432, host='localhost', dbname='postgres', database='tax',
                             user='postgres', password='postgres',
                             mincached=2, maxconnections=2)
    # 从连接池中取一个连接
    conn = pool.connection()
    cur = conn.cursor()
    cur.execute("select count(*) as count from pg_stat_activity")
    rs = cur.fetchone()
    print list(rs)
    cur.close()
    # 不会影响这个连接池的连接数量. pool.close()关闭连接池,会关闭所有连接.
    conn.close()

if __name__ == '__main__':
    while True:
        main()
        time.sleep(1)
发现连接数始终不是变,单个连接的close,不会影响到这个连接池。
 
试试将上面cur.close() conn.close()注释掉,会导致连接数增加吗?
答案也是不会. pool是局部变量,变量销毁,连接会自动关闭。
 
得到结论:
* 单个连接关闭,不会影响连接池
* 连接池变量释放,或者程序停止,连接会自动关闭
 
 
可推断webpy中定有全局变量,不释放而导致连接增加.
 
顺着这个思路阅读web源码,发现web.ctx是个TreadedDict类型
class ThreadedDict(threadlocal):
    """
    Thread local storage.

        >>> d = ThreadedDict()
        >>> d.x = 1
        >>> d.x
        1
        >>> import threading
        >>> def f(): d.x = 2
        ...
        >>> t = threading.Thread(target=f)
        >>> t.start()
        >>> t.join()
        >>> d.x
        1
    """
    # 原因就在这里
    _instances = set()

    def __init__(self):
        ThreadedDict._instances.add(self)

    def __del__(self):
        ThreadedDict._instances.remove(self)

    def __hash__(self):
        return id(self)
    ....
原来它有个静态属性ThreadedDict._instances保存每个实例,而每个实例中又保存web.database产生的PooledDB对象.
所以pool一直不释放。
 
所以原因就是: web.database每次新建一个PooledDB对象,而对象又保存在全局变量TreadedDict._instance中.
由于不断新建连接池,又不释放连接池,最终导致连接数不断增加。
 
 
webpy如何解决这个问题?
使用polling参数,禁止连接池
db = web.database(port=5432, host='localhost', dbn='postgres', db='tax',
                  user='postgres', pw='postgres', pooling=False)
 
这上面得出的结论对oracle和其它类型的数据库同样有效.
 
 
 

评论(1) 阅读(2754)

线程里的全局变量threading.local

2014年1月09日 17:09

通常情况下,子线程可以访问主线程中的变量,并且可以修改它。
如果线程希望有自己的变量,不允许其它线程修改。这种情况怎么办?
利用threading.local模块就可以解决这种问题。
#encoding=utf-8
from threading import local, Thread, currentThread

threadeddict = local()
threadeddict.name = "main"

ctx = {"username": "abc"}


class LocalThread(Thread):
    def run(self):
        print "-----local-------"
        print currentThread()
        print threadeddict.__dict__   # 可以访问到主线程中的变量,但是访问不了它的内容
        print ctx                     # 变量和内容都可以访问
        threadeddict.name = self.getName()  # 改变值不会影响主线程
        print threadeddict.__dict__

if __name__ == '__main__':
    print "-----main-------"
    print currentThread()
    print threadeddict.__dict__

    A = LocalThread()
    A.start()
    A.join()

    print "-----main-------"
    print currentThread()
    print threadeddict.__dict__
 
ctx变量对子线程而言有两个特征:
1.全局的(子线程内部都可访问)
2.可以访问修改的
 
threadeddict对子线程而言只有一个特征:全局的。只剩下一个全局变量名。
 

 

Tags: python
评论(0) 阅读(1355)

计算上月并且返回格式为xx

2014年1月07日 16:31

要求计算上月,并且返回格式为XX的

now = datetime.datetime.now()
last = now - datetime.timedelta(days=now.day)
print last.strftime('%m')

计算下个月

import calendar
import datetime

now = datetime.datetime.now()
max_days = calendar.monthrange(now.year, now.month)[1]
next = now + datetime.timedelta(days=max_days - now.day + 1)
print next.strftime('%m')

评论(0) 阅读(575)

libpq-fe.h:没有那个文件或目录

2014年1月03日 09:13

安装psycopg2出现这个错误,需要安装postgresql-devel

sudo yum install postgresql-devel

评论(0) 阅读(732)