前言

最近需要在Jupyter中写一个类库,其中有一个文件实现从数据库中读取空间数据并加载为Feature对象,Feature对象是cartopy封装的geometry列表,能够方便的用于作图等。因为有很多数据是经常用到的,所以就写了很多常量将数据事先读好供用户直接调用,这样造成的一个问题是每次加载该页面的时候很慢,于是我就考虑可以写个Cache来缓存这些数据,这在其他情况下是再正常不过的需求,然而我却在这里折腾半天,踏了坑,坑里还有水,再也没有出来。。。在这里我简单分析一下失败的原因,如果有人有能解决的方案或者我有什么说的不对的地方,欢迎批评指导!

折腾过程

首先我考虑这个应该是写个Cache类,其中加入一个字典,于是找到了这样一块代码,初步看了一下代码没有问题,于是Copy上:

#coding=utf-8
from time import time
class Cache:
'''简单的缓存系统'''
def __init__(self):
'''初始化'''
self.mem = {}
self.time = {} def set(self, key, data, age=-1):
'''保存键为key的值,时间位age'''
self.mem[key] = data
if age == -1:
self.time[key] = -1
else:
self.time[key] = time() + age
return True def get(self,key):
'''获取键key对应的值'''
if key in self.mem.keys():
if self.time[key] == -1 or self.time[key] > time():
return self.mem[key]
else:
self.delete(key)
return None
else:
return None def delete(self,key):
'''删除键为key的条目'''
del self.mem[key]
del self.time[key]
return True def clear(self):
'''清空所有缓存'''
self.mem.clear()
self.time.clear()

很清晰的一段代码,并且加入了缓存时间,应当能满足我的要求的,在此页面定义了一个变量,创建一个FEATURE_CACHE对象如下:

FEATURE_CACHE = Cache()

这样我在需要缓存的页面只要先判断是否在缓存内,是则直接读取,否则使用原来的逻辑读取数据库并存入缓存即可,改造如下:

if FEATURE_CACHE.get(ds_id) != None:
return FEATURE_CACHE.get(ds_id)
else:
...
geo_feature = ...
FEATURE_CACHE.set(ds_id, geo_feature)
return geo_feature

逻辑上清晰易懂,然后尝试调用。新建一个jupyter页面,多次调用,很好,只有第一次比较慢,再次调用就非常快,本以为这就解决了问题,我也是灵光一闪,既然我是全局缓存那就再开一个页面试试吧,于是又新建了一个jupyter页面,大跌眼镜的事情出现了,居然也是第一次调用非常慢,这是什么逻辑,为什么这里面没有缓存。然后经历了无数次加输出信息调试、重启kernel调试、staticmethod方法、单例等均达不到效果,单例的代码如下:

class Cache:
__instance = None __lock = threading.Lock() # used to synchronize code mem = {}
time = {} def __init__(self):
"disable the __init__ method" '''简单的缓存系统''' def set(self, key, data, age=-1):
'''保存键为key的值,时间位age'''
self.mem[key] = data
if age == -1:
self.time[key] = -1
else:
self.time[key] = time() + age
return True def get(self,key):
'''获取键key对应的值'''
if key in self.mem.keys():
if self.time[key] == -1 or self.time[key] > time():
return self.mem[key]
else:
self.delete(key)
return None
else:
return None def delete(self,key):
'''删除键为key的条目'''
del self.mem[key]
del self.time[key]
return True def clear(self):
'''清空所有缓存'''
self.mem.clear()
self.time.clear() @staticmethod
def getInstance():
if not Cache.__instance:
Cache.__lock.acquire()
if not Cache.__instance:
Cache.__instance = object.__new__(Cache)
object.__init__(Cache.__instance)
Cache.__lock.release()
return Cache.__instance

这样就是不再创建Cache的实例,而是直接调用Cache.getInstance()。可想而知这样也是不行的。于是折腾一番后我得出这么一个结果。

结果与原理

当我们在一个jupyter页面中调用某个python库的时候,只要在这个jupyter页面中不重新启动内核,则已经加载过的模块会自动缓存(是python的缓存,并非我写的缓存),重启内核相当于打开一个新的jupyter页面,并且在重新打开一个jupyter页面时,即使其他jupyter页面已经加载过了相应的调用,也不会缓存,会再次去执行程序,这样我写的Cache类就没有用了。所以结论就是在jupyter中我的Cahce缓存类加不加效果是一样的。那么原理是什么呢?

其实很简单,只是我刚开始对python的运行机理和生命周期等不太熟悉,才走了这个弯路,折腾一番大概明白了。首先普通的python程序使用python xx.py启动的时候这样写Cahce肯定是可行的,能够实现全局缓存,因为这是在一个application内部,加载过的python文件会编译成pyc,再次加载的时候会直接调用此pyc而不会重新执行,并且整体是共享内存的。而在jupyter中每一个jupyter页面都相当于启动了一个application,所以他们相互之间是隔离的,即无法共享pyc文件,也无法共享内存,于是重新打开一个jupyter页面就是一个新的Cache,这样写不写Cache得到的结果是一致的。

总结

当然可以考虑采用文件缓存的方式,即首次读取的时候将数据库内容加载到本地文件,再次调用的时候读取文件,然而并没有尝试这样会快多少,并且本身访问量就不大,数据库是完全能抗住的,于是不知道这样的缓存有多少意义。当然也可以使用redis、memcache等缓存件,但是这样就整大发了,没必要使用jupyter了吧。以上是我对此问题的个人见解,欢迎大家提出宝贵意见,不甚感激!

Jupyter(Python)中无法使用Cache原理分析的更多相关文章

  1. Python中的浮点数原理与运算分析

    Python中的浮点数原理与运算分析 本文实例讲述了Python中的浮点数原理与运算.分享给大家供大家参考,具体如下: 先看一个违反直觉的例子:     >>> s = 0. > ...

  2. Python 中生成器的原理

    生成器的使用 在 Python 中,如果一个函数定义的内部使用了 yield 关键字,那么在执行函数的时候返回的是一个生成器,而不是常规函数的返回值. 我们先来看一个常规函数的定义,下面的函数 f() ...

  3. Guava Cache 原理分析与最佳实践

    前言 目前大部分互联网架构 Cache 已经成为了必可不少的一环.常用的方案有大家熟知的 NoSQL 数据库(Redis.Memcached),也有大量的进程内缓存比如 EhCache .Guava ...

  4. MySQL的Query Cache原理分析

    QueryCache(下面简称QC)是根据SQL语句来cache的.一个SQL查询如果以select开头,那么MySQL服务器将尝试对其使用QC.每个Cache都是以SQL文本作为key来存的. 原理 ...

  5. python中fork()函数生成子进程分析

    python的os module中有fork()函数用于生成子进程,生成的子进程是父进程的镜像,但是它们有各自的地址空间,子进程复制一份父进程内存给自己,两个进程之 间的执行是相互独立的,其执行顺序可 ...

  6. Java中的递归原理分析

    解释:程序调用自身的编程技巧叫做递归.        程序调用自身的编程技巧称为递归( recursion).递归做为一种算法在程序设计语言中广泛应用. 一个过程或函数在其定义或说明中有直接或间接调用 ...

  7. Python中关于XML-RPC原理

    SimpleXMLRPCServer模块为XML-RPC服务端的写入提供了一个基本的框架.利用SimpleXMLRPCServer服务器既可以一直空闲,也可以利用CGIXMLRPCRequestHan ...

  8. python中fork()函数生成子进程分析-乾颐堂

    python的os module中有fork()函数用于生成子进程,生成的子进程是父进程的镜像,但是它们有各自的地址空间,子进程复制一份父进程内存给自己,两个进程之 间的执行是相互独立的,其执行顺序可 ...

  9. Python中闭包的原理

    定义: 如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure). 简单闭包的例子: 下面是一个使用闭包简单的例子,模拟一个计数器,通过将 ...

随机推荐

  1. 在Debian9(linux)上使用 的 python 3 IDLE(已经安装了python 2.7 的情况下)

    在Debian9(Stable)中默认安装了python2.7和pytohon3.5两个版本,但是没有IDLE,本人想用pytihon3.5的IDLE,将本次解决问题在此Mark一下, 首先,执行 s ...

  2. python+selenium自动化软件测试(第12章):Python读写XML文档

    XML 即可扩展标记语言,它可以用来标记数据.定义数据类型,是一种允许用户对自己的标记语言进 行定义的源语言.xml 有如下特征: 首先,它是有标签对组成:<aa></aa> ...

  3. python 关于列表的增删改查及个别的命令

    names = ["a","b","c","d","e","e","a ...

  4. EAGO科技人工智能+澳洲MSPL外汇平台招商

    天下财经 首席运营商 EAGO外汇人工智能简介:我们将历史数据导入算法引擎,加入因子(外汇中使用的各种技术指标及各个国家的货币政策等)让计算机通过二元遗传基因.深度神经网络等算法,由机器自主深度学习. ...

  5. python 魔法方法(学习过程的笔记)

    有小伙伴会问,什么是python的魔法方法,python的魔法方法有什么用呢, 它们在面向对象的Python的处处皆是.它们是一些可以让你对类添加"魔法"的特殊方法. 它们经常是两 ...

  6. MySQL(九)之数据表的查询详解(SELECT语法)二

    上一篇讲了比较简单的单表查询以及MySQL的组函数,这一篇给大家分享一点比较难得知识了,关于多表查询,子查询,左连接,外连接等等.希望大家能都得到帮助! 在开始之前因为要多表查询,所以搭建好环境: 1 ...

  7. Spring Cloud Netflix多语言/非java语言支持之Spring Cloud Sidecar

    Spring Cloud Netflix多语言/非java语言支持之Spring Cloud Sidecar 前言 公司有一个调研要做,调研如何将Python语言提供的服务纳入到Spring Clou ...

  8. CAP和BASE理论

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt370 1. CAP理论 2000年7月,加州大学伯克利分校的Eric Bre ...

  9. 《Java从入门到放弃》JavaSE入门篇:异常

    异常!!!看看生活中的异常例子: 正常情况下,从家到公司上班,只需要20分钟!但如果在路上碰到堵车或修路或车突然自燃等问题,那就没办法正常去上班了.其中堵车或修路或车突然自燃等问题就属于异常. 碰到异 ...

  10. poj 1149经典网络流构图

    题意:m个猪圈,n个客户,每个客户给出选则猪圈的钥匙和需要购买猪的个数,其中每次客户购买时客户选则的猪圈数量可以相互更换,问最大购买数量. 思路:以客户作为除源点汇点之外的点,然后对于每个猪圈从源点连 ...