6月 19

现代 A7HD 使用感受—太垃圾

  我在 2012-04-29 18:36 买了 现代 A7HD,现在2012年6月19日,用了不到两个月,就出问题了。要插着电源才能开机,但是开机后显示电池还有51%的电,开了机一拔电源,机器就关机,再插电源机器就是重新开机。找淘宝的店主联系了一下,被告知要升级固件解决。我到官方网站,升级了6月15日公布的的固件更新。但是到30%左右还是自动关机,并且如果一天不用的话,即使有40%多的电量仍旧不能开机。按照淘宝店主的提醒拨打了4000189600,客服说让我邮到深圳去检查,并且来往邮费都是客户承担。我问如果维修了邮回来后,还不能解决问题或出现其它问题怎么办,客服回答可以换新机,但是来往邮费也要买家承担。最后客服十分不高兴,说如果对处理不满意,就直接找卖家解决。这个服务真是太垃圾了。
  后来淘宝店主和我说把机器邮到他那,他来处理。我没有邮,原因:一、几百块的东西不值得耽误这么多时间。二、即使真的返厂就能解决根本问题吗?搞不好又有其他问题,来回修几次,邮费都比机器贵了。这种服务态度,能让你相信他们对自己的产品负责吗?开始没有问题,用了一段时间久出问题,大家相信升级固件能解决问题吗?我觉得这个是硬件问题,已经有部分电池坏了,固件升级只是在程序上将当前损坏问题屏蔽掉。大家可以观察一下,即使处理掉,使用时间也应该是大幅缩减。即使淘宝店主的态度再好,对于这种垃圾厂家我也是没有信心。

image

6月 18

tornado学习笔记(二)

主要模块

web – FriendFeed 使用的基础 Web 框架,包含了 Tornado 的大多数重要的功能
escape – XHTML, JSON, URL 的编码/解码方法
database – 对 MySQLdb 的简单封装,使其更容易使用
template – 基于 Python 的 web 模板系统
httpclient – 非阻塞式 HTTP 客户端,它被设计用来和 web 及 httpserver 协同工作
auth – 第三方认证的实现(包括 Google OpenID/OAuth、Facebook Platform、Yahoo BBAuth、FriendFeed OpenID/OAuth、Twitter OAuth)
locale – 针对本地化和翻译的支持
options – 命令行和配置文件解析工具,针对服务器环境做了优化

底层模块

httpserver – 服务于 web 模块的一个非常简单的 HTTP 服务器的实现
iostream – 对非阻塞式的 socket 的简单封装,以方便常用读写操作
ioloop – 核心的 I/O 循环

  首先在建立一个mysql数据库,库名为test_tornado,建立一个有用户表,表中包含用户名密码,脚本如下。

CREATE TABLE `user` (
  `id` int(100) NOT NULL DEFAULT '0',
  `user` varchar(20) DEFAULT NULL,
  `passwd` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
);


INSERT INTO `user` VALUES ('0', 'simonzhang', '123456');

  建立监听,和url,启停脚本见上次笔记。
main.py

#!/bin/python
#-*- coding:utf-8 -*-
# Filename:    main.py
# Revision:    1.0
# Date:        2012-06-14
# Author:      simonzhang
# web:         www.simonzhang.net
# Email:       simon-zzm@163.com
### END INIT INFO
import sys
import tornado.ioloop
import tornado.web
from login import *


application = tornado.web.Application([
    (r"/", LoginHandler),
],  cookie_secret="61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=")


if __name__ == "__main__":
    listen_port =  sys.argv[1]
    application.listen(listen_port)
    tornado.ioloop.IOLoop.instance().start()

  在同级目录下建立templates目录,在templates目录下建立login.html。login.html的源码是


   
      {{title}}
   
   
        
User Name:
Password:

  做一个简单的验证页面,只是个简单判断,学习使用,权限认证和cookie部分不做记录了。编辑login.py源码

#!/bin/python
#-*- coding:utf-8 -*-
# Filename:    main.py
# Revision:    1.0
# Date:        2012-06-14
# Author:      simonzhang
# web:         www.simonzhang.net
# Email:       simon-zzm@163.com
### END INIT INFO
import sys
import tornado.ioloop
import tornado.locale
import tornado.web
import tornado.database
from dbmodel import *


class LoginHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("templates/login.html", title="simonzhan.net")
    def post(self):
        try:
            name = self.get_argument("login_username")
            passwd = self.get_argument("login_password")
            _passwd = get_passwd(name)
            if _passwd is not None:
                if _passwd == _passwd:
                    self.write("hello %s" % (_passwd))
                else:
                    self.render("templates/login.html", title="simonzhan.net")
            else:
               self.render("templates/login.html", title="simonzhan.net")
            #self.write("hello %s" % (name))
        except:
            self.render("templates/login.html", title="simonzhan.net")
            return

  因为要查数据,所以要用到database,将数据库部分放到一文件中去。编辑dbmodol.py源码如下:

#!/bin/env python
# -*- coding: utf-8 -*-
# Filename:    main.py
# Revision:    1.0
# Date:        2012-06-14
# Author:      simonzhang
# web:         www.simonzhang.net
# Email:       simon-zzm@163.com
### END INIT INFO
from tornado import database


def get_passwd(user_name):
    db = database.Connection("192.168.1.41","test_tornado","123456","simonzhang")
    for projects in db.query("SELECT user,passwd from user where user='%s'" % user_name):
        return projects.passwd

  启动服务,在ie里能看到页面,输入正确的账户密码,可以看到经典的话了。基本框架完成,剩下的慢慢学习,慢慢发挥了。

6月 17

tornado学习笔记(一)

学习地址 http://www.tornadoweb.cn/documentation
http://sebug.net/paper/books/tornado/#tornado-walkthrough。
本文只是学习笔记

一、部署

  开始学习。服务器使用内部pc服务器,地址为192.168.1.41,操作系统为centos 5.6,python2.6。安装tornado环境太简单了,两条命令如下:
# easy_install tornado
# yum install pycurl

  环境安完,开始学习。按照说明拷贝代码命名为main.py代码如下:

import tornado.ioloop
import tornado.web

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

application = tornado.web.Application([
    (r"/", MainHandler),
])

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

运行服务
python main.py

直接在浏览器中输入http://192.168.1.41:8888,看到了经典的东西了。tornado是单进程,在多核服务器上,我器多个进程,然后用nginx做负载。自己写了一个启停服务的脚本。

启停服务脚本如下,命名为”main.sh”,运行脚本后会在同级目录产生一个“main.port”文件,文件中记录启动的端口号列表。

#!/bin/sh
#
# Filename:    main.sh
# Revision:    1.0
# Date:        2012-06-14
# Author:      simonzhang
# web:         www.simonzhang.net
# Email:       simon-zzm@163.com
#
### END INIT INFO

# Source function library.
. /etc/profile

# Set the base value
listen_line=4
listen_start=8880

# 
CWD=`pwd`
cd $CWD

# See how we were called.
case "$1" in
  start)
        /bin/rm -rf main.port
	for (( i=0 ; i<${listen_line} ; i++)); do
            listen_port=$[${listen_start}+${i}]
            echo ${listen_port} >> main.port
            python main.py ${listen_port} &
	done
        echo "start ok !"
        ;;
  stop)
        get_port_line=`/bin/cat main.port`
        for i in ${get_port_line};do
             now_pid=`/bin/ps -ef|grep ${i}|grep -v grep|awk ' ''{print $2}'`
             /bin/kill -9 $now_pid
        done
        echo "stop"
        ;;
  status)
        get_port_line=`/bin/cat main.port`
        for i in ${get_port_line};do
             now_pid=`/bin/ps -ef|grep ${i}|grep -v grep`
             if [ -z "${now_pid}" ] ; then
                 echo ${i} "is stop"
             else
                 echo ${now_pid}
             fi
        done
	;;
  restart)
	$0 stop
	$0 start
	;;
  *)
        echo $"Usage: $0 {start|stop|restart|status}"
        exit 1
esac

exit $rc

  将启动文件也做一下修改,mian.py代码如下:

#!/bin/python
#-*- coding:utf-8 -*-
# Filename:    main.py
# Revision:    1.0
# Date:        2012-06-14
# Author:      simonzhang
# web:         www.simonzhang.net
# Email:       simon-zzm@163.com
### END INIT INFO
import sys
import tornado.ioloop
import tornado.web


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


application = tornado.web.Application([
    (r"/", MainHandler),
])


if __name__ == "__main__":
    listen_port =  sys.argv[1]
    application.listen(listen_port)
    tornado.ioloop.IOLoop.instance().start()

  现在配置nginx,只列出了http中的连接配置

   #######################www.grabproxy.com
   upstream  www_test_com {
            server 192.168.1.41:8880;
            server 192.168.1.41:8881;
            server 192.168.1.41:8882;
            server 192.168.1.41:8883;
       }
   server {
        listen       80;
        server_name 192.168.1.41;
        location / {
        proxy_cache_key $host$uri$is_args$args;
        proxy_redirect          off;
        proxy_set_header        X-Real-IP $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header        Host $http_host;
        client_max_body_size   10m;
        proxy_connect_timeout  300;
        proxy_send_timeout     300;
        proxy_read_timeout     300;
        proxy_buffer_size      16k;
        proxy_buffers          4 32k;
        proxy_busy_buffers_size 64k;
        proxy_temp_file_write_size 64k;
        access_log  logs/access.log  main ;
        access_log on;
        proxy_pass              http://www_test_com;
        }
     }

  重新加载nginx配置,在浏览器里输入http://192.168.1.41,又看到经典页面。 

简单做个压力测试,结果如下,cup主频3.0。

# ./ab -c1000 -n10000 http://192.168.1.41:8880/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 192.168.1.41 (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests

Server Software: TornadoServer/2.1.1
Server Hostname: 192.168.1.41
Server Port: 8880

Document Path: /
Document Length: 21 bytes

Concurrency Level: 1000
Time taken for tests: 8.013 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 1790000 bytes
HTML transferred: 210000 bytes
Requests per second: 1247.92 [#/sec] (mean)
Time per request: 801.331 [ms] (mean)
Time per request: 0.801 [ms] (mean, across all concurrent requests)
Transfer rate: 218.14 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 166 680.6 0 3004
Processing: 20 115 46.5 100 873
Waiting: 20 115 46.5 100 873
Total: 47 281 686.0 100 3325

Percentage of the requests served within a certain time (ms)
50% 100
66% 101
75% 106
80% 124
90% 290
95% 3105
98% 3134
99% 3149
100% 3325 (longest request)

但是通过nginx负载后性能却下降,部分结果如下:
Failed requests: 9609
(Connect: 0, Receive: 0, Length: 9609, Exceptions: 0)
Write errors: 0
Non-2xx responses: 391
Total transferred: 2256920 bytes
HTML transferred: 274515 bytes
Requests per second: 714.81 [#/sec] (mean)

总结:tornado性能不错,但是nginx负载后直接使用proxy转发,耗费在连接上的资源比较高。这个和资料里介绍的出入较大,以后再找详细原因。如果单从性能讲nginx+uwsgi+django的组合效率不错。如果要使用tornado在多核服务器上工作,有两个方案,一使用lvs做底层的负载,二在开发中在代码里使用多线程进行处理。tornado对于wsgi文档中原文“Tornado 对 WSGI 只提供了有限的支持,即使如此,因为 WSGI 并不支持非阻塞式的请求,所以如果你使用 WSGI 代替 Tornado 自己的 HTTP 服务的话,那么你将无法使用 Tornado 的异步非阻塞式的请求处理方式。比如 @tornado.web.asynchronous、httpclient 模块、auth 模块,这些将都无法使用。”还要说明,node.js是非常快,但是node.js+express后效率并不理想,闲人可以测试一下。

听说gevent也不错,但是粗看了一下,没有看到中文文档。tornado对于个人来说,这个性能已经满足需要了。开始进一步学习。

6月 13

读《天朝的崩溃》

  毛海建先生的《天朝的崩溃》中包含大量历史文献。在尊重时事的基础上,分析了当时背景下管理层的想法,也结合当今的研究做了“事后诸葛亮”。高中历史教材上只有两页纸的内容,让我们对事件和人物的认识非好及坏。事物是复杂的,各种问题间包含着各种矛盾。通过毛先生的讲述让我对这段历史有个根详细的认识。
image
  

6月 09

python 统计一段字符串中某字符串出现次数

统计一段字符串中某字符串出现次数。如查询“It takes only a minute to get a crush on someone,an hour to like someone,and a day to love someone- but it takes a lifetime to forget someone”中出现“takes”出现的次数。

str = ‘It takes only a minute to get a crush on someone,an hour to like someone,and a day to love someone- but it takes a lifetime to forget someone’
get_count = count_find_str(str, 'takes')
print get_count

函数如下

def count_find_str(str,find_str):
    _str = str
    _find_str = find_str
    _pos = _str.find(_find_str)
    _find_str_count = 0
    while _pos != -1:
        _find_str_count = _find_str_count + 1
        _pos = _pos + len(_find_str)
        _pos = _str.find(_find_str, _pos)
    return _find_str_count

注意:在单词过短的情况下会出现错误,如统计“a”,除了“a”本身作为单词出现,在单词中的“a”字母也会被统计。所以,建议统计字符串短写的长单词。我是为了统计数据库连接数所写的这个,实际测试还是很好用。