执行python fact.py
,打开浏览器,键入http://localhost:8888/fact?n=50,可以看到浏览器输出了
608281864034267560872252163321295376887552831379210240000000000
,如果我们不提供n参数,访问http://localhost:8888/fact
,可以看到浏览器输出了400: Bad Request
,告诉你请求错误,也就是参数少了一个。
使用Redis
上面的例子是将缓存存在本地内存中,如果换一个端口再其一个阶乘服务,通过这个新端口去访问的话,对于每个n,它都需要重新计算一遍,因为本地内存是无法跨进程跨机器共享的。
所以这个例子,我们将使用Redis来缓存计算结果,这样就可以完全避免重复计算。另外我们将不在返回纯文本,而是返回一个json,同时在响应里增加字段来说名本次计算来源于缓存还是事实计算出来的。另外我们提供默认参数,如果客户端没有提供n,那就默认n=1。
import json
import redis
import tornado.ioloop
import tornado.web
class FactorialService(object):
def \_\_init\_\_(self):
self.cache = redis.StrictRedis("localhost", 6379) *# 缓存换成redis了*
self.key = "factorials"
def calc(self, n):
s = self.cache.hget(self.key, str(n)) *# 用hash结构保存计算结果*
if s:
return int(s), True
s = 1
for i in range(1, n):
s *= i
self.cache.hset(self.key, str(n), str(s)) *# 保存结果*
return s, False
class FactorialHandler(tornado.web.RequestHandler):
service = FactorialService()
def get(self):
n = int(self.get_argument("n") or 1) *# 参数默认值*
fact, cached = self.service.calc(n)
result = {
"n": n,
"fact": fact,
"cached": cached
}
self.set_header("Content-Type", "application/json; charset=UTF-8")
self.write(json.dumps(result))
def make\_app():
return tornado.web.Application([
(r"/fact", FactorialHandler),
])
if __name__ == "\_\_main\_\_":
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
当我们再次访问http://localhost:8888/fact?n=50,可以看到浏览器输出如下
{"cached": false, "fact": 608281864034267560872252163321295376887552831379210240000000000, "n": 50}
,再刷新一下,浏览器输出{"cached": true, "fact": 608281864034267560872252163321295376887552831379210240000000000, "n": 50}
,可以看到cached字段由true编程了false,表明缓存确实已经保存了计算的结果。我们重启一下进程,
再次访问这个连接,观察浏览器输出,可以发现结果的cached依旧等于true。说明缓存结果不再是存在本地内存中了。
圆周率计算服务
接下来我们再增加一个服务,计算圆周率,圆周率的计算公式有很多种,我们用它最简单的。
我们在服务里提供一个参数n,作为圆周率的精度指标,n越大,圆周率计算越准确,同样我们也将计算结果缓存到Redis服务器中,避免重复计算。
*# pi.py*
import json
import math
import redis
import tornado.ioloop
import tornado.web
class FactorialService(object):
def \_\_init\_\_(self, cache):
self.cache = cache
self.key = "factorials"
def calc(self, n):
s = self.cache.hget(self.key, str(n))
if s:
return int(s), True
s = 1
for i in range(1, n):
s *= i
self.cache.hset(self.key, str(n), str(s))
return s, False
class PiService(object):
def \_\_init\_\_(self, cache):
self.cache = cache
self.key = "pis"
def calc(self, n):
s = self.cache.hget(self.key, str(n))
if s:
return float(s), True
s = 0.0
for i in range(n):
s += 1.0/(2*i+1)/(2*i+1)
s = math.sqrt(s*8)
self.cache.hset(self.key, str(n), str(s))
return s, False
class FactorialHandler(tornado.web.RequestHandler):
def initialize(self, factorial):
self.factorial = factorial
def get(self):
n = int(self.get_argument("n") or 1)
fact, cached = self.factorial.calc(n)
result = {
"n": n,
"fact": fact,
"cached": cached
}
self.set_header("Content-Type", "application/json; charset=UTF-8")
self.write(json.dumps(result))
class PiHandler(tornado.web.RequestHandler):
def initialize(self, pi):
self.pi = pi
def get(self):
n = int(self.get_argument("n") or 1)
pi, cached = self.pi.calc(n)
result = {
"n": n,
"pi": pi,
"cached": cached
}
self.set_header("Content-Type", "application/json; charset=UTF-8")
self.write(json.dumps(result))
def make\_app():
cache = redis.StrictRedis("localhost", 6379)
factorial = FactorialService(cache)
pi = PiService(cache)
return tornado.web.Application([
(r"/fact", FactorialHandler, {"factorial": factorial}),
(r"/pi", PiHandler, {"pi": pi}),
])
if __name__ == "\_\_main\_\_":
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
因为两个Handler都需要用到redis,所以我们将redis单独抽出来,通过参数传递进去。另外Handler可以通过initialize函数传递参数,在注册路由的时候提供一个字典就可以传递任意参数了,字典的key要和参数名称对应。我们运行python pi.py
,打开浏览器访问http://localhost:8888/pi?n=200
,可以看到浏览器输出{"cached": false, "pi": 3.1412743276, "n": 1000}
,这个值已经非常接近圆周率了。
一、Python所有方向的学习路线
Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照下面的知识点去找对应的学习资源,保证自己学得较为全面。
二、Python必备开发工具
工具都帮大家整理好了,安装就可直接上手!
三、最新Python学习笔记
当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。
四、Python视频合集
观看全面零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。
五、实战案例
纸上得来终觉浅,要学会跟着视频一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
六、面试宝典
简历模板
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!