随机优先与权重(续)
Posted ccat
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了随机优先与权重(续)相关的知识,希望对你有一定的参考价值。
随机、优先与权重(续)
写完上文《随机、优先与权重》后,我顺便写了一个 Python 版本的 pycroupier——毕竟我们这个人工智能组的主要编程语言是 Python。在测试的时候,我发现一个很糟糕的问题。
Damping 和 Invert 这两个主要算法,居然有缺陷,因为之前的测试逻辑不严谨,边界处理的问题没有暴露出来。
首先是以前的 damping 并不会选中第一个元素。这是一个很简单的计算问题,做一下平移就能解决
class Damping[T](val random: Random) extends Poker[T]
override def select(cards: Seq[T]): Option[Int] =
if (cards == null || cards.isEmpty)
return None
if (cards.size == 1)
return Some(0)
val range = Math.log(cards.size + 1)
val value = Math.exp(random.nextDouble() * range)
Some(Math.floor(value).intValue() - 1)
不过没有第一时间发现这个问题,确实是因为测试逻辑写的不严谨。过去的测试逻辑是执行完算法逻辑后,遍历计数器字典,打印结果。但是如果某个元素一次也没有被选中过,就不会出现在字典中,正确的逻辑应该是:
it should "select more elements while more nearer front user damping" in
val counter: mutable.Map[Int, Int] = new mutable.TreeMap[Int, Int]()
val croupier = Croupier.damping[Int]
for (_ <- 0 until 100000)
val element = croupier.randSelect(elements)
element should not be None
element.foreach value =>
counter.put(value, counter.getOrElse(value, 0) + 1)
for (num <- elements)
info(s"damping select $num times $counter.getOrElse(num, 0)")
当然,在scaled/rank算法中,如果某一个元素的权重是0,那么它也不会被选中,这是符合设计的。
最后,我观察了 invert 的计算结果,感觉这个曲线还是过于陡峭了,对于(我自己)常见的业务来说,是一个太过激进的做法。于是我把 invert 改成了反向的damping。
相关的内容我已经在前文中做了修改,jaskell core、jaskell dotty 和 jaskell java8的相关修改也已经发布。不过测试代码不严谨导致问题没有及时发现,这倒是值得记一笔。
顺便说一下 Python 版本 pycroupier,这个版本的实现比较简单,因为 python 是动态类型,很多在静态类型中的设计都没有意义。rank/scale合并为rank,并且rank只要求是一个函数(或者实现了 __call__(self, item)
方法的对象)。同样在Scala和Java版中用来构造 croupier 的静态(object)方法,也写成了函数。
再就是draw_one
抽取一个元素,draw
则提取一组,不提供分组为(selected, rest)
的操作,因为 Python 的默认 list 并不提供只读保证,Python 的使用者也习惯了利用高度的动态特性。如果确实需要,可以将原有的 list 复制之后使用,这也是我实现 select
的方法。
也因为这个原因,使用 ZipRanked 类型时要注意,此时使用的 rank 函数需要返回整数,因为 ZipRank 要构造一个键为权重的字典,如果使用浮点数 rank,那么意喻着rank值来自一个稠密的实数区间,恐怕 zip 就失去了意义。
最后,pycroupier 的安装和使用非常简单,从 pypi 就可以安装:
pip install pycroupier
导入 pycroupier 包就可以使用
In [1]: import pycroupier
In [2]: data = ["b", "e", "h", "d", "f"]
In [3]: croupier = pycroupier.damping()
In [4]: croupier.draw(data, 2)
Out[4]: ['d', 'b']
In [5]:
上面这段代码演示了在 IPython 里执行 damping 选择的效果。
最后,如果大家有深入了解过 Python 的标准库,它提供了 shuffle、choice这样的基本操作,可以用于构造对列表的随机操作,但是这些操作都是基于平均概率的。
http2续
HTTP/2给我们的好处
- 多路复用 :一次TCP握手,多个同域并行请求,请求和响应同时发送接受,然后再拼装组合,不阻塞;
- 优先级和依赖性(Priority) :可以请求的时候告知服务器端,资源分配权重,优先加载重要资源;
- 服务器推送(Server Push) :根据客户端需求,服务端主动推送资源,减少请求耗时;
HTTP1.1中,所有为了减少请求而做出的HACK,在HTTP/2中都已经不再是性能优化考虑的主要点了。
分域名
HTTP1.1时代,我们经常会用多个域名来做请求优化,因为浏览器同域名下会有并行请求数限制(根据浏览器不同2-8个,比如IE6只有两个),然而DNS解析又得额外花时间,所以以前对域名的个数还需要根据各自网站找一个平衡点。HTTP/2就不用理会这个了,因为多路复用,并行请求不再是瓶颈,收敛了域名后还能减少DNS解析时间,所以HTTP/2中我们不用再细分域名了。
接口请求
HTTP1.1的时候,我们经常会根据当前的页面,将请求合并成一个。HTTP/2中可以更细粒度的组合你的接口,不用再根据某个页面所需数据,来组合一个专门的无意义的接口了(不用合并请求),不怕请求多,就怕单个请求太慢。
内联资源
有人说Server Push就是另外一种形式的内联,其实不是,内联太Low了,完全无法跟它来比较。
首先我们来回顾下,HTTP1.1时代,我们为什么要内联,因为我们希望减少请求,我们为了加快首页的渲染速度,甚至会把首页第一屏的样式内联到HTML中,一起返回,加速首屏渲染。然而当有人想改动首屏任何内容,无论多小都得重新替换掉整个页面。
在HTTP/2下我们可以通过推送的方式给你想要的资源,跟你的HTML请求一块儿返回给你,不仅如此,push的内容还可以进行缓存,多页面共享。
以上是关于随机优先与权重(续)的主要内容,如果未能解决你的问题,请参考以下文章