和妹子聊天聊得不咋地,有一句没一句的,哎。。。这事还得坚持.....不提妹子的事,长期斗争,还得慢慢来。。。必须要有耐心。。。不扯这个了,扯点有用的
1. meta_data保存在什么地方?
经过今天的研究,我发现,meta_data的所有数据都存在数据库中,有这么几张相关的表:instances, instance_metadata,instance_system_metadata;
instances中有:
instance_metadata保存的是meta数据,也就是键值对,我通过实验发现,调用nova meta <instance-id> set/delete XXX=YYY后,实例(虚机)通过169.254.169.254:80/openstack/latest/meta_data.json能得到meta的键值对,也就是说,只要调用nova meta成功,键值对立刻有了,或者删除掉了。
instance_system_metadata:
2) 从上文中的url中提取数据,比如name
#从数据库中的数据中得到一个虚机的实例
instance = self.compute_api.get(ctxt, id,
want_objects=True)
#允许api方法从一个db查询中存储一个对象,这个db查询方法是被api extensions使用的,并且是重复的api请求
#我猜测就是,第一次查询比较慢,之后这个object保存在数据库中,不用重新生成,而是直接使用,相当于一个cache缓存
req.cache_db_instance(instance)
#不详
policy.enforce(ctxt, 'compute:update', instance)
#最终调用 nova/objects/instance.py 的父类 base.NovaObject方法update,就是把instance(字典(各种键值对的集合))displayname = 新名字
instance.update(update_dict)
#调用 nova/objects/instance.py 中的save方法:
# 基本上就是将变化保存数据库
instance.save()
eventlet.
spawn
(func,*args,**kw) 开一个greenthread跑func
eventlet.
spawn_n
(func,*args,**kw)开一个greenthread跑func
,但不知道greenthread何时终止,运行速度快
eventlet.
spawn_after
(seconds,func,*args,**kw)开一个greenthread跑func
eventlet.connect(addr, family=2, bind=None) 客户端sockets,连接对象
eventlet.listen(addr,family=2, backlog=50) 服务端sockes,监听对象
eventlet.wrap_ssl(sock,*a, **kw) 配置ssl,通过PyOpenssl
classeventlet.
GreenPool 线程池管理并发线程
eventlet.serve(sock,handle, concurrency=1000) 建立服务器,scck为listen对象,handle为处理函数,最后一个为最大并发支持数
有accept方法;
eventlet.
import_patched
(modulename,*additional_modules,**kw_additional_modules) 向线程导入标准模块的绿色版本
eventlet.
monkey_patch
(all=True,os=False,select=False,socket=False,thread=False,time=False) 全局向线程导入系统模块
仔细一分析,得到如下结论:对于服务端程序,先listen,后创建greenpoll(所谓的线程池),最后调用serve,创建服务器,这就解决了上面的2所提出的问题。
5. 一个服务端eventlet如何服务多个地址?
1)一般都是一个server监听一个地址:端口,也就是一个套接字,但是,这是C的一些习惯,比如我要调用:localhost:8090/server/create与localhost:8090/server/update,返回的结果就会不同,那么这个server是如何处理的呢?
让我们来猜一下:
http协议中必然有一个字段是标示要访问的具体地址,根据这个地址的不同,调用不同的处理函数进行处理,并返回结果。
也就是说,可能在server中,有一个dispatcher,它能够将消息发给不同的处理程序
我们揭晓谜底,看看别人wsgi是怎么做的:
最简单的:
a. server = listen //socket
b. pool = GreenPool //线程池
c. new_sock, address = server.accept //与client通信的sock, 与client sock地址
d. pool.spawn_n(handle,new_sock) //handle是处理函数
完整的代码:
- import eventlet
- c=eventlet.connect(('127.0.0.1', 6000))
- while True:
- data=raw_input('Enter data:')
- c.sendall(data)
- rc=c.recv(1024)
- print rc
- import eventlet
- def handle(client):
- while True:
- c = client.recv(1024)
- print c
- client.sendall(c)
- server = eventlet.listen(('0.0.0.0', 6000))
- pool = eventlet.GreenPool(10000)
- while True:
- new_sock, address = server.accept()
- pool.spawn_n(handle, new_sock)
这个程序一定是可以多线程服务的,但是这个却没有用http协议,我看行~
那么上述提出的问题如何解决呢?例子是socket通信,但是我们要走http协议,那很简单,其实就是约定一下收发包的格式就行了~
wsgi服务器:
wsgi.server()这个方法中,第一个参数就是socket,就是所谓的listen socket,第二个就是得到连接后的处理函数,其他都是optional的,因此,我们有理由认为,wsgi.server完全是封装了eventlet中的accept,spawn等等函数
但是处理函数的写法是有一定之归的:
def XXX(env, start_response):
必须先start_response(code,type)
return
在这个处理函数中,就可以对/server/update或者/server/create进行处理了
if env['PATH_INFO'] != '/':
start_response('404 Not Found',[('Content-Type','text/plain')])
return ['Not Found\r\n']
eventlet.import_patched('httplib2') //所谓的打补丁??
eventlet.monkey_patch(socket=True,select=True)
start_response('200 OK',[('Content-Type','text/plain')])
return ['Hello World!\r\n']
wsgi.server(eventlent.listen(('',8090)),hello_world)
基本上可以这么说,eventlet spawn和wsgi.serve其实是相对应的,差不多~
wrap的内容
所谓的装饰器,这个我今天仔细看过一边,看看是否能够说得出来
1. 产生的原因:
def hello()
print "hello world"
但是 想知道这个函数print执行所需的时间,因此
def hello():
time1 = time.time()
print "hello world"
time2 = time.time()
print time2 - time1
每个函数都需要进行一次计算执行时间的运算,结果就是,所有的函数都在函数前和尾加上这些代码,效率太低了,是否有解决的办法?
def hello():
print "hello world"
def timefunc(func):
time1 = time.time()
func()
time2 = time.time()
print time2-time1
timefunc(hello)
但是,还是觉得不方便,因为写代码的时候要处处都写timefunc,而且可能还得传不同的参数,觉得很麻烦
有没有一种方法,它能够不执行这个语句,而是将制作好的函数返还给原函数,从而实现对原函数的改造?
def timefunc(func):
def wrapper():
time1 = time.time()
func()
time2 = time.time()
print time2-time1
return wrapper
hello = timefunc(hello)
hello()
将timefunc当成了一个创造函数的函数,而不是执行函数的函数
python更彻底的解决了这个问题:
@timefunc
def timefunc(func):
def wrapper():
time1 = time.time()
func()
time2 = time.time()
print time2-time1
return wrapper
@timefunc
def hello():
print "hello world"
hello()
实际上,@timefunc相当于:hello = timefunc(hello)
那么对于有参数的怎么办呢?我们再进一步
1)hello函数带有参数
def timefunc(func):
def wrapper(word):
time1 = time.time()
func(word)
time2 = time.time()
print time2-time1
return wrapper
@timefunc
def hello(word):
print word
hello("lihao")
方法是,在wrapper后面要跟参数,和hello的一样,毕竟其实是hello = timefunc(hello) hello = wrapper
2) 多个wrapper怎么破?
def timefunc2(func):
def wrapper2(word):
func(word)
print "i dont know"
return wrapper2
def timefunc(func):
def wrapper(word):
time1 = time.time()
func(word)
time2 = time.time()
print time2-time1
return wrapper
@timefunc2
@timefunc
def hello(word):
print word
hello("lihao")
#结果
lihao
0.0
i dont know
先执行timefunc再执行timefunc2?这种说法不正确,应该这么说,
timefunc2在外层,timefunc在里层,因此,并不是timefunc先执行,而是说,反而timefunc2先执行,因为timefunc返回的是一个方法,而不是执行方法,相当于
@timefunc2
@timefunc
hello = timefunc2(timefunc(hello)) 先执行timefunc(hello),但是只是返回一个函数指针,正在执行是在timefunc2中才被执行的!!
3.装饰器中本身有参数