3月 29

linux下python、go、C库处理图片缩放效率对比

  找到go语言的源码
https://github.com/nfnt/resize
http://code.google.com/p/gorilla/source/browse/lib/appengine/example/moustachio/resize/resize.go?r=3dbce6e267e9d497dffbce31220a059f02c4e99d

  使用’go get ‘安装需要使用git。如果是centos 6 直接安装’yum install git’。但是我的是CentOS 5 还要手动安装一下。
# yum install -y gcc make curl curl-devel zlib-devel openssl-devel perl perl-devel

cpio expat-devel gettext-devel
# wget http://codemonkey.org.uk/projects/git-snapshots/git/git-latest.tar.gz
# tar zxvf git-latest.tar.gz
# cd git-2013-03-28/
# autoconf
# ./configure
# make && make install
# git –version

  git安装完成,开始测试。我的环境,python2.6,go1.0.2,ImageMagick是C/C++语言开发使用也比较广泛。直接用命令测试。。使用一张150k 510×382的图片做测试。缩成宽300的等比例缩小图。

# go get github.com/nfnt/resize

go 测试代码

package main

import (
    "github.com/nfnt/resize"
    "image/jpeg"
    "os"
)

func main() {
    // open "test.jpg"
    file, err := os.Open("test.jpg")
    if err != nil {
        print("Open File Error")
    }

    // decode jpeg into image.Image
    img, err := jpeg.Decode(file)
    if err != nil {
        print("Not image file")
    }
    file.Close()

    // resize to width 1000 using Lanczos resampling
    // and preserve aspect ratio
    m := resize.Resize(300, 0, img, resize.Lanczos3)

    out, err := os.Create("test_go.jpg")
    if err != nil {
        print("Save Image Error!")
    }
    defer out.Close()

    // write new image to file
    jpeg.Encode(out, m, nil)
}

python 测试代码

#!/bin/env python
# -*- coding:utf-8 -*-
# --------------------------------
# Filename:    cut_image.py
# Revision:    1.1
# Author:      simon-zzm
# Web:         www.simonzhang.net
# Email:       simon-zzm@163.com
# --------------------------------
import Image


def main():
    file = Image.open('test.jpg')
    w = file.size[0]
    h = file.size[1]
    re_data = file.resize((300, int(h/(float(w)/300))),)
    re_data.save('test_py.jpg', 'JPEG',)


if __name__ == '__main__':
    main()

  在linux下使用time进行测试结果
# time python cut_image.py

real 0m0.051s
user 0m0.040s
sys 0m0.009s

# time go run cut_image.go

real 0m2.736s
user 0m2.695s
sys 0m0.039s

# time convert -resize 300x test.jpg test_c.jpg

real 0m0.073s
user 0m0.070s
sys 0m0.002s

-rw-r–r– 1 root root 150332 Jul 16 2012 test.jpg
-rw-r–r– 1 root root 12929 Mar 28 23:13 test_go.jpg
-rw-r–r– 1 root root 13087 Mar 28 23:13 test_py.jpg
-rw-r–r– 1 root root 58591 Mar 28 23:14 test_c.jpg

总结:GO使用这个方法作为图片缩放的处理速度和python处理速度的差距太大了。烦请高手指点如何处理。不过GO的语法还是比较简单,值得学习。之前做的多语言简单累加计算测试,GO效率还是比较高,所以处理业务逻辑处理的效率还应该不错。
源码下载

1月 08

python 连接hbase存、取图片

  连接hbase1.0.4需要使用Thrift,我用的是python2.6。
  安装thrift。下载地址https://dist.apache.org/repos/dist/release/thrift/0.9.0/thrift-0.9.0.tar.gz解压后安装命令。
在hbase服务器上,确保hbase服务已经启动。在thrift目录中,用管理员运行一下命令安装。
./configure
make
make install

  安装完毕生成hbase的client代码命令格式如下,
thrift –gen
登陆到hbase的权限进入
$ cd hbase/src/main/resources/org/apache/hadoop/hbase/thrift

生成python的
$ thrift –gen py Hbase.thrift
再生成一个C的学习备用,与本文无关
$ thrift –gen c_glib Hbase.thrift

将gen-py文件夹下的hbase文件夹拷贝到要连接hbase的服务器的python目录下,我用的是python2.6,自己手动安装的。命令如下
cp -R hbase /usr/local/lib/python2.6/site-packages/

拷贝完毕用import导入 hbase成功。开始写代码了。参考hbase里的例子在hbase/src/examples/中。

  我的任务就是把某个目录下,以jpg结尾的图片放到hbase里,因为图片名没有重复,所以用图片名做row name。hbase手动建表’hbase(main):013:0> create ‘img’, ‘data:”。

  首先统计一下照片的数量。这个image目录下只有jpg的图片,使用匹配只是备将来使用。下面只是测试脚本,不关心业务逻辑。

# find /image/ -name \*.jpg -type f |wc -l
13140

# du -s -h /image
303M /image/

  本地共有13140张照片共303M,写入hbase测试脚本如下:

#!/bin/bash 
# -------------------------------
# Revision:
# Date:        2012-12-11 
# Author:      simonzhang 
# Email:       simon-zzm@163.com 
# Web:         www.simonzhang.net 
# -------------------------------

import os
import re

from thrift.transport import TSocket  
from thrift.transport import TTransport  
from thrift.protocol import TBinaryProtocol  
   
from hbase import Hbase  
from hbase.ttypes import *

#### base set
find_path=(r'/image/',
           )

class HbaseWrite():
    def __init__(self):
        self.tableName = 'img'
        self.transport = TSocket.TSocket('192.168.100.100', 9090)
        self.transport = TTransport.TBufferedTransport(self.transport)
        self.transport.open()
        self.protocol = TBinaryProtocol.TBinaryProtocol(self.transport)
        self.client = Hbase.Client(self.protocol)

    def createTable(self, tableName):
        col1 = ColumnDescriptor(name="data:",maxVersions=1)
        self.client.createTable(tableName,[col1])

    def write(self, PicPath, PicName):
        row = PicName.split('.')[0]
        _data = PicName.split('.')[1]
        PicData = open('%s/%s' % (PicPath, PicName), 'rb').read()
        # 此处需要注意格式,网上的格式报错,少个参数报错如下
        # TypeError: mutateRow() takes exactly 5 arguments (4 given)
        self.client.mutateRow(self.tableName, row, [Mutation(column="data:%s" % _data, value=PicData)], {})

    def read(self, tableName, PicName):
        row = PicName.split('.')[0]
        data_type = PicName.split('.')[1]
        get_data = self.client.get(tableName, row, 'data:%s' % data_type, {})[0]
        if get_data:
            return get_data.value
        else:
            return "Error"


def main(_path):
    WHB = HbaseWrite()
    WHB.createTable()
    find_file=re.compile(r"^[0-9a-z]*.jpg$")
    find_walk=os.walk(_path)
    for path,dirs,files in find_walk:
        for f in files:
            if find_file.search(f):
                path_name=path
                file_name=f
                WHB.write(path_name, file_name)


if __name__ == "__main__":
    for get_path in find_path:
        main(get_path)

开始测试脚本
# time python hbase_test.py

real 1m15.471s
user 0m4.881s
sys 0m2.867s

到hbase里查看写入的数量,证明已经完全写入。
hbase(main):001:0> count ‘img’
:
:
:
13140 row(s) in 10.2780 seconds

2013-5-16. 因为对hadoop理解不足。以下写的有问题,提醒大家注意。

hbase使用hadoop进行存储,查看hadoop的磁盘使用量。
26K namenode1/
298M u01/

  我的内存给namenode可以使用25G。根据以上数据计算结果如下:
((25*1000*1000)/26)*298= 286538461M = 286538G = 286 T

  如果每台服务器有三块1T存储硬盘,此集群可以有95台服务器。共存储此类照片大约为12634615360张。内网测试,写入速度3.9M。

  注:有一点需要注意,写入的数据删除后磁盘空间也不会释放,原理应该改和mongodb一样,但是没有仔细查看。

8月 08

go语言环境准备

开始使用的是编译好的包,由于CentOS系统64位的版本过老,编译总是报错,所以最后还是使用源码编译。具体操作非常简单。
先安装需要的工具,如果已有就不用安装了。
# yum install mercurial bison gcc libc6-dev ed gawk make
解压源码包,执行编译命令,配置环境变量即可。
我使用root用户,将源码包直接放在/usr/local/目录下。操作记录如下
# tar zxvf go1.0.2.src.tar.gz
# cd go/src/
# ./all.bash
到用户的home目录里编译.bash_profile,如果要所有用户都能用,就直接编辑/etc/profile。
export GOROOT=/usr/local/go
export GOARCH=amd64
export GOOS=linux

PATH=$PATH:$HOME/bin:/usr/local/go/bin

到此已经可以用了,随便搞个hello world试试。
/etc/profile配置
export GOROOT=/usr/local/go
export GOBIN=/usr/local/go/bin
export GOARCH=amd64
export GOOS=linux
export PATH=$GOBIN:$PATH

5月 06

scrapy 学习笔记 一

  很多python开发都在用scrapy框架开发抓取,我也算学习一下。虽然笔记序号为一,但是能不能坚持下去还不知道,写着看吧。官方网址:http://scrapy.org/。官方接受scrapy是纯python做的高效的web抓取框架,网络爬虫,后提取相关页面的数据。scrapy可以用于数据挖掘、监控和自动化测试等工作。据说google的大部分爬虫也是用python写的,但是不知道是否用了这个框架。可以肯定的是,这个框架能做很多事、很大,我只会用到很简单一部分。我做笔记是为自己学习记录,既不系统也不全面,建议大家到官方下载pdf的文档,进行学习,我也是通过pdf文档学习,并使用其中的例子修改为自己的形成笔记。为了不引起争议,直接用自己的站进行抓取学习。
  开始学习了,linux的环境,是CentOS5,windows的环境是win7,python都是2.6,因为scrapy支持2.6、2.7,不支持3.X。直接使用easy_install安装,但是windows上安装的是0.14.3,linux上安装的0.12,官方网站上最新的开发版本是0.15。不知道为什么差距这么大。为了方便学习直接手动下载0.15,安装到linux上。

tar zxf Scrapy-X.X.X.tar.gz
cd Scrapy-X.X.X
python setup.py install

  在linux上安装有警告,关于ssl的,如下

Running pyOpenSSL-0.13/setup.py -q bdist_egg –dist-dir /tmp/easy_install-rx8P0H/pyOpenSSL-0.13/egg-dist-tmp-g7Da22
warning: no previously-included files matching ‘*.pyc’ found anywhere in distribution
OpenSSL/ssl/connection.c: In function ‘ssl_Connection_set_context’:
OpenSSL/ssl/connection.c:289: 警告:隐式声明函数 ‘SSL_set_SSL_CTX’
OpenSSL/ssl/connection.c: In function ‘ssl_Connection_get_servername’:
OpenSSL/ssl/connection.c:313: 错误:‘TLSEXT_NAMETYPE_host_name’ 未声明 (在此函数内第一次使用)
OpenSSL/ssl/connection.c:313: 错误:(即使在一个函数内多次出现,每个未声明的标识符在其
OpenSSL/ssl/connection.c:313: 错误:所在的函数内只报告一次。)
OpenSSL/ssl/connection.c:320: 警告:隐式声明函数 ‘SSL_get_servername’
OpenSSL/ssl/connection.c:320: 警告:赋值时将整数赋给指针,未作类型转换
OpenSSL/ssl/connection.c: In function ‘ssl_Connection_set_tlsext_host_name’:
OpenSSL/ssl/connection.c:346: 警告:隐式声明函数 ‘SSL_set_tlsext_host_name’
error: Setup script exited with error: command ‘gcc’ failed with exit status 1

  直接下载pyopenssl后安装,
http://pypi.python.org/packages/source/p/pyOpenSSL/pyOpenSSL-0.12.tar.gz

  再执行 easy_install -U scrapy,安装成功。
  在windows上除了安装pyopenssl还要w3lib、Twisted,但是处理比较简单,直接easy_install安装,如:C:\Python26\Scripts>easy_install.exe pyopenssl。
  环境搭建完成,毕竟使用的linux服务器,所以还是在linux上学习。开始创建一个抓取项目,项目名为scrapytest.
>scrapy startproject simonzhang
创建项目完毕,目录树如下,:

simonzhang
│  scrapy.cfg               # 整个目录的配置
│
└─simonzhang                # 项目模块,代码都放在这
    │  items.py             # 项目的items文件,相当于格式化抓取的内容,以字典形式返回
    │  pipelines.py         # 项目的pipelines,管理通道,主要是对抓取网页后的数据清洗、验证和入库
    │  settings.py          # 项目的设置文件,
    │  __init__.py
    │
    └─spiders             # 这个目录放的是蜘蛛文件,
            __init__.py

  进入simonzhang目录,编辑simonzhang/items.py

from scrapy.item import Item, Field

class ScrapytestItem(Item):
    # define the fields for your item here like:
    # name = Field()
    title =  Field()
    link = Field()
    desc = Field()
    pass

  编写第一个蜘蛛simonzhang/spiders/frist_simonzhang.py

from   scrapy.spider      import   BaseSpider 

class   DmozSpider (BaseSpider): 
      name  =  "simonzhang_net"     # 蜘蛛的名字,一个项目下每个蜘蛛名字必须是唯一的
      allowed_domains = ["simonzhang.net"] 
      start_urls = ["http://www.simonzhang.net/"]  #下载列表,注意域名后面需要一个“/”因为稍后会用于截取文件名

      def  parse (self,response):   # 抓取和保存的方法
           filename    =  response.url.split("/")[2] 
           open (filename, 'wb').write(response .body)

  进入simonzhang/simonzhang/spiders目录运行下面命令:
scrapy crawl simonzhang_net
  运行完毕,看到目录下已经有一个www.simonzhang.net的文件,打开文件可以看到是抓取为首页的文件。

scrapy 学习笔记 二
http://www.simonzhang.net/?p=1112

2月 17

mysql 升级5.5.20 注意问题记录

当前使用mysql5.1但是有些表情字符不能加入,所以决定将数据库
升级到5.5.20。从官方下载二进制64位工具。
http://dev.mysql.com/get/Downloads/MySQL-5.5/mysql-5.5.20-linux2.6-x86_64.tar.gz/from/http://mysql.cs.pu.edu.tw/

直接解压,将老版本的数据直接拷贝过来,启动数据库。整个过程比较顺利,
数据库已经运行,为了避免以下错误,还需要进行以下操作。

a) 错误1548 – Cannot load from mysql.proc. The table is probably corrupted.

需要对数据进行升级。执行以下命令。
$ mysql_upgrade -u root -p
在出现一堆ok后升级完成。

b) 岁然数据库和数据升级了,还需要修改表的字符集。(根据需要进行修改)

登录mysql,进入相关库,使用如下命令。
> alter table xxxx charset utf8mb4;
当前数据库可以支持iphone表情和奇怪的字符集了。

升级过程注意保存原有配置。