我在CherryPy服务器中构建了一个奇怪的情况,我想帮助理解究竟发生了什么,以及为什么。这是server.py
:
import cherrypy
import os
import threading
class Root(object):
def __init__(self):
self.count = 0;
self.lock = threading.Lock()
@cherrypy.expose
def app(self):
with self.lock:
self.count += 1
return "Call #%d" % (self.count)
if __name__ == '__main__':
cherrypy.quickstart(Root(), "/", {"/": { "tools.staticdir.on": True,
"tools.staticdir.dir": os.getcwd() } })
这是一个非常简单的应用程序,某些状态受互斥锁保护。这是index.html
:
<!doctype html>
<script src=http://code.jquery.com/jquery-1.8.2.js></script>
<script src=index.js></script>
(HTML可以很稀疏 - 请参阅this talk from Paul Irish)以下是index.js
:
function request() {
var cb = function (response) {
console.log(response);
};
$.ajax({
url: "/app",
success: cb
});
}
function go_slow(N, delay) {
if (N > 0) {
request();
window.setTimeout(go_slow, delay, N - 1, delay);
}
}
function go_fast(N) {
var i;
for (i = 0; i < N; i++) {
request();
}
}
window.onload = function () {
//go_slow(100, 0);
go_fast(100);
};
所有这些文件都应该放在同一个目录中。当我启动CherryPy服务器然后访问http://localhost:8080/index.html
时,控制台会显示“Call#1”一词100次,而CherryPy日志会向“/ app”显示一个GET请求。在Firefox中,我看到几个连续的控制台消息,显示“#1”到“#100”。 Firefox的行为是我所期望的,因为我做了100个显式的ajax请求,并且与这些请求相关联的函数应该每次都返回不同的结果。
如果不是go_fast()
我调用go_slow()
- 使用“trampolining”(我认为它被称为)的变体强制ajax请求在不同时间从单独的函数调用发出 - 然后我在Chrome和Firefox上获得“#1”到“#100”行为。
最后,如果我修改CherryPy服务器中的app()
方法接受一个然后忽略的参数,就像这样(注意其他地方没有出现的i
参数):
@cherrypy.expose
def app(self, i):
with self.lock:
self.count += 1
return "Call #%d" % (self.count)
我安排go_fast()
函数通过更改{{"/app/" + i"
向i
(其中"/app"
是循环索引)而不仅仅request()
发出ajax请求1}}和go_fast()
是这样的:
function request(i) {
var cb = function (response) {
console.log(response);
};
$.ajax({
url: "/app/" + i,
success: cb
});
}
function go_fast(N) {
var i;
for (i = 0; i < N; i++) {
request(i);
}
}
然后我再次通过“#100”行为获得“#1”。相反,如果我修改要使用的函数,例如"/app/7"
作为URL(即,使用"/app/" + i
替换上面代码段中的"/app/7"
),我会重复100次“呼叫#1”如在最初的例子中那样。
对我而言,它看起来很像某些东西正在“缓存”唯一的ajax请求的结果,该请求实际上是在最初的情况下(我只看到了“Call#1”100)次)。 Chrome控制台中的“网络”选项卡只显示一个ajax请求,其状态代码为“200 OK”,据我所知,您必须在CherryPy中明确启用服务器端缓存。在这种情况下,Firefox也会产生预期行为的好奇心。
在其他情况下,由于某种原因,这种“缓存”机制被打败了。 Trampolining可能会导致浏览器抛出ajax请求的直接上下文,阻止它“记住”先前对同一URL的请求,同时设想URL需要位置参数只是给每个请求一个唯一的URL,强制实际请求结束,而不是使用任何缓存机制。
任何人都可以具体解释这里发生了什么吗?关于Chrome如何在短时间内处理许多ajax请求,这仅仅是一个特点吗?或者这种情况是否具有有状态的ajax资源是一个致命的问题?
答案 0 :(得分:0)
我认为这是与客户端cache: false
选项结合使用的竞争条件,请记住您的对象Root
在线程池中共享。
按时A
您修改self.count
并按时A
另外X个请求(线程)正在返回A - 1
with
上新修改的参数{{1}} {{1}} 1}}阻止并且没有在此特定请求上返回该新计数。
当正在修改和退出with语句的请求已经在返回时,那么确定返回的数字的重复或不存在的是cherrypy的线程池的处理吞吐量。