Gevent

Gevent

特点:
	是一个基于libev的并发库 它为各种并发和网络相关的任务提供了整洁的API
	基于libev的高效时间循环
	基于greenlet的轻量级执行单元
	重用Python标准库API内容(比如Event Queues)
	socket谢童ssl
	利用线程池或者c-cares来执行DNS查询

a. 进程 线程 协程

进程:
    概念: 进程是正在运行程序的实例
    特点: 具有独立地址空间 是操作系统资源分配的基本单元
    进程上下文: 进程的物理实体与支持进程运行的物理环境,包括:地址空间 系统栈 打开文件表 。。。
    上下文切换: 由一个进程的上下文转到另一个进程的上下文
    系统开销: 运行操作系统程序完成系统管理工作所话费的时间和空间
    一个进程可以包括多个线程

线程:
	- 线程是程序执行的最小单位
	- 多线程的优点: 提高程序的并发性
协程:
	- 协程可以认为是一种用户态的线程,与系统提供的线程不同点是 他需要主动让出cpu时间,而不是由系统进行调度,即控制权在程序员手上。

优缺点:
	- 进程创建销毁成本高
	- 线程开销比进程低,但切换成本高,线程间同步变复杂。
	- 协程不陷入内核的情况进行上下文切换,没有同步问题,但需要手动切换。

下图解释:
    进程是有状态的 刚启动时就绪态,如果进程调度算法调度到这个进程 就会变成执行态。
    分配的算法是有时间片的 当时间片使用完 会继续切回就绪态
    如果时间片没有使用完 当有IO发生就会阻塞态 阻塞完成 继续切回用户态

 

b. 阻塞 非阻塞 同步 异步

阻塞与非阻塞:
     
    网络IO
        - 对于网络IO主要指socket,socket是进程间通信的一种方法 对于阻塞与非阻塞的情况就是在使用socket中在调用它的API时它的connect read write 会发生阻塞,也可以设置为非阻塞。
        - socket会在connect/read/write时发生阻塞
    阻塞
        - 阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回
    非阻塞
        - 非阻塞指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回


同步与异步:

	同步:
		同步就是发生调用时,一定等待结果返回,整个调用才结束。

	异步:
		异步就是发生调用后,立即返回,不等待结果返回,被调用者通过状态/通知来通知调用者,或通过回调函数处理这个调用。


	同步异步 与 阻塞非阻塞区别:
		阻塞/非阻塞 它们是程序在等待消息(无所谓同步或者异步)时的状态。
		同步/异步 是程序获得关注消息通知的机制。

		同步阻塞: 效率最低(日志程序)
		同步非阻塞: 效率也不高(需要轮询)
		异步阻塞: 一般模式线程回调
		异步非阻塞: IOCP

 

connect 阻塞做的操作
	客户端和服务端做交互的时候,客户端连接服务器,connect时候阻塞会自动打开,会向服务端发送一个序列号,服务端接受后处于阻塞。

数据接受阻塞
	应用层recvfrom调用过程中会发生一个系统调用。系统调用会陷入内核里面。如果没有数据准备好,会等待数据直到数据准备好,内核得到数据把数据复制到用户空间,在返回。

c. 并发 并行

#并发
	并发是指两个或多个事件在同一时间间隔发生。就是同时处理很多事情,比如串行同时处理一件事情。
	在单核系统中,为了提高cpu利用率,系统采用时间片轮询等调度方式,对多个线程轮换执行,在宏观上看线程是同时执行的 从微观上看某一时刻只执行一个线程。在发生资源竞争或者大量的上下文切换会导致性能消耗。

d. monkey patch

# monkey patch

	- 在动态语言中,不去改变源码而对功能进行追加和变更就叫做 Monkey Patching(猴子补丁)
	1. 追加功能
	2. 功能变更
	3. 修正程序错误
	4. 增加钩子,在执行某个方向的同时执行一些其他的处理 如打印日志 实现AOP等

	#模块
		- socket
		- dns
		- time
		- select
		- thread
		- os
		- ssl
		- subprocess
		- sys
		- builtins
		- signal
	默认阻塞的模块都被替换成非阻塞,协作式的。
	gevent支持异步协作的域名解析系统。
	time.sleep只是协作内休眠,并不阻塞线程。
import gevent
from gevent import monkey

urls = ["http://www.baidu.com","http://www.zhihu.com","http://www.xiaohuar.com/"]
import urllib2
import timeit
def print_head(url):
    print("start %s"%url)
    gevent.sleep(0)
    data = urllib2.urlopen(url).read()
    print("%s:%s bytes: %r" %(url,len(data),data[:50]))


def test():
    jobs = [gevent.spawn(print_head,url) for url in urls]
    gevent.joinall(jobs)

monkey.patch_all()      #加上这行效率明显提升

print timeit.Timer(stmt='test()',setup="from __main__ import test").timeit(number=10)
实例演示

e. gevent.server

# 服务器端
import socket
import sys

host = "localhost"
port = 5000

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

s.bind((host,port))
s.listen(100)
while True:
    conn,addr = s.accept()
    print 'connected with',addr[0], ':',str(addr[1])
    data = conn.recv(1024)
    print data
    conn.close()

s.close()



# 客户端

from gevent import monkey
monkey.patch_all()
import gevent
import socket

def do_connect(addr,index):
    sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    sock.connect(addr)
    gevent.sleep(0.5)
    sock.send("hello world")

addr = ('localhost',5000)

greenlets = []
num = 1
for i in xrange(num):
    g = gevent.spawn(do_connect,addr,i)
    greenlets.append(g)
gevent.joinall(greenlets)
普通服务器 客户端
# gevent server

from gevent.server import StreamServer
import gevent
from gevent import monkey
monkey.patch_all()
import socket

def handler(sock,addr):
    while True:
        data = sock.recv(1024)
        if not data:
            print addr, "closed"
            return
        print "get ",data

server = StreamServer(('127.0.0.1',3000),handler)

server.serve_forever()
gevent server

f. gevent.WSGIServer 

WSGI 介绍

	web服务器网关接口(Python Web Server Gateway Interface 缩写为WSGI) 是为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口

WSGI server

	WSGI server所做的工作仅仅是将从客户端收到的请求传递给WSGI application,然后将WSGI application的返回值作为响应传给客户端。
	WSGI application 可以是Flask,Diango 等web框架。

  

 

 

  

 

  

  

posted @ 2017-11-04 00:24  golangav  阅读(613)  评论(0编辑  收藏  举报