背景
最近做了一些要求效率的工作,用到了一些没接触过的或者较少接触的东西,把他们记录如下
同步
- 需求:做一个url和id一一对应的项目,给定url,有唯一id与之对应。但是不能用md5生成的结果,原因是32位还是太长
- 那只能用数据库,如果数据库没有保存,就分配一个新的id给他,这个id是递增的。
- 数据库用的redis,跨服务器也可以方便使用
- id的获取是redis提供的锁,一是跨服务器使用;二是需要可靠,做到真正的锁的效果。
- 然后递增的id又用了urlsafe_base64自行做了一个转化,得到一个字母数目较少的结果
# 不完全代码如下
def _getId(self):
key, maxid_key = 'maxid_lock', 'Img_max_id'
lock_value = self.redis_lock.lock(key)
maxid = int(self.rds.incr(maxid_key))
self.redis_lock.unlock(key, lock_value)
iid = self.n2s(maxid)
return iid
def get_iid(self, url):
# 目前情况,如果相同的url同步执行的话,仍没有好办法
trycount = 0
iid = self.pika.get(url)
while trycount < 2:
if iid: break
if not (isinstance(iid, str) and len(iid) < 15):
Tiid = self._getId()
iid = 'i_%s' % Tiid
# 防止不同条目但相同jpg url的情况同步取iid的问题
# 这里多检测一次
Piid = self.pika.getset(url, iid)
if Piid and Piid != iid:
# 重写回去
iid = Piid
self.pika.set(url, Piid)
trycount += 1
return iid
def feed_generator(self, ipt):
iid = self.get_iid(ipt['name']) # 这里防止
if iid:
self.pika_iid2url.set(iid, ipt['name'])
return iid
else:
raise
def n2s(self, n):
s = []
while n > 0:
m = n % cfg.NHASH
c = cfg.SAFEHASH[m]
s.append(c)
n = int(n / cfg.NHASH)
s.reverse()
return ''.join(s)
数据库es和redis的cache
- 需求:构建实时插入和访问的数据库
- 数据库是组内其他人维护的elasticsearch,但是es的响应时间不稳定,插入的数据不能立即被访问到,时间差从0.0n 毫秒到10毫秒。相比之下redis的响应速度要快的多。所以并发访问服务传入的信息条目先用redis收集起来,在做一个排队处理,使得进入es的都是不同的条目。redis搜集最近2s内的数据,那可以完全的避开es的这一缺陷。
- 代码如下
python的并发和并行
- 并发可看作是thread线程相关的,比如一个人同时赶牛和羊去吃草高IO操作做的比较好;但是同时拉大车和推手推车这种高度消耗算力的就做的不好;并行是process进程,这些事情由两个人来做,不管是赶牛羊还是推拉车都可以很好的完成。
- 并发操作python提供了thread和concurrent这些封装好的库,不过还是有actor这种并发或并行的方式,可以避免每次都要花费一些资源来开启、关闭进程或线程。代码如下
- 当然还包括协程,协程可以看做是这样:去银行柜台,把事先约定好的材料交进去,看他一顿操作之后,你有了一张银行卡,然后再去干别的。协程更倾向于用一个信号这种方式把运行逻辑切割开。我交进去材料,也不用管办没办好或者怎么办,反正交了;之后再去干别的。