2014年12月

Python网络编程三:协程gevent

python的协程中要应用yield,常用于生成器:yield语句代替return返回一个值,则定义了一个生成器函数。 生成器函数使用yield语句返回一个值,然后保存当前函数整个执行状态,等待下一次调用。 在协程中使用到yield,我觉得就是利用这个特性吧。

什么是协程?

子例程的起始处是惟一的入口点,一旦退出即完成了子例程的执行,子例程的一个实例只会返回一次。 协程可以通过yield来调用其它协程。通过yield方式转移执行权的协程之间不是调用者与被调用者的关系,而是彼此对称、平等的。 协程的起始处是第一个入口点,在协程里,返回点之后是接下来的入口点。子例程的生命期遵循后进先出(最后一个被调用的子例程最先返回);相反,协程的生命期完全由他们的使用的需要决定。

含糊不清有点,看下线程和协程吧:

协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示调度。协程和线程的区别是:协程避免了无意义的调度,由此可以提高性能,但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力。

另外直知乎上面有个答案讲了“进程、线程、协程”,参考一下:参考

好了,可以进入Gevent了。 我一开始使用Gevent只是使用“异步”,因为快! 如下代码所示:

import gevent.monkey
gevent.monkey.patch_socket()

import gevent
import requests


urls=[]
urls.append('http://myreading.sinaapp.com/yige/?offset=0')
urls.append('http://myreading.sinaapp.com/zhihu/?offset=0')
urls.append('http://myreading.sinaapp.com/meiwen/?offset=0')
urls.append('http://myreading.sinaapp.com/36kr/?offset=0')
urls.append('http://myreading.sinaapp.com/xinli/?offset=0')
urls.append('http://myreading.sinaapp.com/guokr/?offset=0')
urls.append('http://myreading.sinaapp.com/yp136/?offset=0')

def fetch(url,pid):
response = requests.get(url)
json_result = response.json()
title = json_result[0]['title']
print 'Process %s: %s' %(pid,title)

def synchronous():
for i in range(len(urls)):
fetch(urls[i],i)

def asynchronous():
threads = []
for i in range(len(urls)):
threads.append(gevent.spawn(fetch,urls[i],i))
gevent.joinall(threads)

print('Asynchronous:')
asynchronous()

print('Synchronous:')
synchronous()

关于Gevent的更多知识,以后在慢慢研究,贴个链接:Gevent指南

Python网络编程二:多线程循环Server

上一节,实现的只是简单的Socket API,从这一节开始陆续介绍python网络方面的其他东西。 今天来完善上一次的server服务器,这次我们加入多线程。 科普 thread:线程 python 里面的 thread 接口:thread

服务器通过开创建多线程,来服务多个客户端。 threadserver:

#coding=utf-8
import socket
import thread

def main():
listen_sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM,)
listen_sock.bind(('127.0.0.1', 6000))
listen_sock.listen(5)#accept()应答之前进入队列等待
#循环等待 创建子线程
while True:
conn_sock, client_addr = listen_sock.accept()
thread.start_new(serve, (conn_sock, client_addr))

def serve(conn_sock, client_addr):
print('connected from %s:%s' % client_addr)
input = conn_sock.recv(1024)
#循环等待 客户端通信
while 'done' != input.strip():
conn_sock.sendall(input)
input = conn_sock.recv(1024)
conn_sock.sendall('bye!\n')
conn_sock.close()

main()

Python网络编程一:简单socket API

python的socket模块和C语言的Berkeley套接字(socket)API一脉相称,这就不介绍了。其实其他语言如Java之类的socket操作基本类似。 先简单介绍API:(谷歌检索拿来一张图) 既然这是系列的第一篇,先上简单的socket server和client 的代码: server:

import socket
serversocket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
serversocket.bind(('127.0.0.1',6000))
serversocket.listen(1)
clientsocket,clientaddress=serversocket.accept()
print 'Connection from',clientaddress
while 1:
data=clientsocket.recv(1024)
if not data:break
print 'Received from client:',repr(data)
print 'Echo:',repr(data)
clientsocket.send(data)
clientsocket.close()
serversocket.close()

client:

import socket
clientsocket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
try:
clientsocket.connect(('127.0.0.1',6000))
while 1:
data=raw_input('>')
clientsocket.send(data.encode())
if not data:break
newdata=clientsocket.recv(1024)
print 'Received from server:',repr(newdata)
finally:
clientsocket.close()

说它简单,是因为只是循环服务器,也没有多线程。以后再补充!

erlang语言

想着把node.js也搬上博客了,就再装逼一点来点erlang吧。
“whisper”中国版-“耳语”公司的后端语言是erlang。我与“耳语”的联系其实也是挺有意思的。 我认识一位师兄在“耳语”做运营,我参加过“耳语”的线下活动,跟技术经理王宇成聊过,那次谈话让我受益匪浅。之后我投了“耳语”的简历,再跟大牛通话过一次,那次他给了我笔试题,两道。 拿到题我立马跑去图书馆借了一本《Erlang程序设计》,花了三天把答案发了回去。大牛回邮件问我什么时间有空,再通一次电话。我回复了他,结果我等了一个礼拜也没收到电话,我甚至再给他发邮件问他我是否还有实习机会。一直没收到回复,然后就没有然后了。。。。。。

Erlang:

“是一种通用的并行程序设计语言,运作于虚拟机的解释型语言,Erlang也支持脚本方式执行。在程序设计范型上,Erlang属于多重范型编程语言,涵盖函数式、并行及分布式。循序运行的Erlang是一个及早求值, 单次赋值和动态类型的函数式编程语言。”---维基百科

面向并发?

“Erlang的并发特性源自语言本身而非操作系统。它把现实世界模拟成一系列的进程,期间仅靠交换消息进行互动,由此Erlang简化了并行编程。在Erlang的世界中,存在并行进程但是没有锁,没有同步方法,也不存在共享内存污染的可能,因为Erlang根本没有共享内存。 Eralng程序可以有几百万个超轻量级的进程组成。这些进程可惜运行在单处理器、多核处理器或者多处理网络上。”---《Erlang程序设计》

好了,这也是一门很“牛”的语言。我在入门的时候一开始没有适应“函数式编程”的习惯。 下面贴两道题: 第一道:列表交叉

-module (interleave).
-export ([main/0]).
% -compile(export_all).

%   interleave.erl 
%   主程序入口:main()  interleave:main().
%   通过修改MyList获得更多测试

loop(0,_)->
    [];
loop(Num,TempList)->
    %得到递归的列表
    N=[Tx||[_|Tx]<-TempList],
    %取子列表的头
    [Hx||[Hx|_]<-TempList]++loop(Num-1,N).

main() ->
    %MyList可以任意
    MyList=[[1,2,3],[4],[5,6,7,8]],
    io:format("Old list:~w~n",[MyList]),
    %%由最长子列表,确定循环次数 
    Num=length(lists:max(MyList)),
    NewList=loop(Num,MyList),
    io:format("New list:~w~n",[NewList]).

python代码无压力:

l=[[1,2,3],[4],[5,6,7,8]]
new_l=[]
for x in xrange(len(max(l))):
    new_l.extend(map(lambda x:x and x.pop(0),l))
print [x for x in new_l if x !=[]]

第二道:5个立方数

-module (cube).
-export ([main/0]).
% -compile(export_all).

%   cube.erl 
%   主程序入口:main()  cube:main().
%   启用进程字典 用来加快速度

split(N)->
    %将数字转成列表
    lists:map(fun(X)->X-48 end,integer_to_list(N)).

loop(Num)->
    Cube=Num*Num*Num,
    %为保证速度 启用进程字典 key--数字序列 通过排序保证相同的key 
    Key=lists:sort(split(Cube)),
    Temp=case get(Key) of
        undefined->[];
        L->L
    end,
    %在key相同的情况下 保证value列表元素的增加 
    %L是先前的列表结果 所以知道列表元素是从前面添加的
    Value=[Cube|Temp],
    if
        %length若为5 则为所求
        length(Value)==5->
            %将Value倒置就能取到最大值
            io:format("The smallest cube five permutations:~w~n",[lists:last(Value)]),
            init:stop();
        true->
            %length<5则继续增加Value的length,同时更新C(key)对应的value
            put(Key,Value),
            loop(Num+1)
    end.
 
main()->
    %节省时间 从405开始 
    loop(405).
    

node.js入门与介绍

关于“node.js”基本概念请自行Google搜索,先推荐"知乎"的一个问答使用 Node.js 的优势和劣势都有哪些? 因为最近在阅读网络编程相关,必须的弄明白服务器的相关知识,就周边的了解了一下node.js。 这个很厉害:

传统的网络服务技术,是每个新增一个连接(请求)便生成一个新的线程,这个新的线程会占用系统内存,最终会占掉所有的可用内存。而 Node.js 仅仅只运行在一个单线程中,使用非阻塞的异步 I/O 调用,所有连接都由该线程处理,在 libuv 的加分下,可以允许其支持数万并发连接(全部挂在该线程的事件循环中)。 `

关于异步:


/*
异步调用思想
*/
function Person () {
    this.think=function (callback) {
        setTimeout(function () {console.log('thinking....');callback()
        },5000);
    }
    this.answer=function () {
        console.log('I am answering other question');
    }   
}
var person=new Person();
person.think(function () {
    console.log('thinking 5 second,get the right answer!')
});
person.answer();

hello world:

/*
开启http服务器
*/
var http=require('http');
http.createServer(function (rep,res) {
    res.writeHead(200,{'Content-Type':'text/plain'});
    res.end('Hello World\n');
}).listen(1337,"127.0.0.1");

console.log('Server running at http://127.0.0.1:1337');

基础概念和知识以后再续。