限制CherryPy中的并行进程? [英] Limit parallel processes in CherryPy?
问题描述
我有一个运行在BeagleBone Black上的CherryPy服务器.服务器生成一个简单的网页,并执行本地SPI读/写(硬件接口).该应用程序将一次在具有1-2个客户端的本地网络上使用. 我需要防止CherryPy类函数在完成之前被调用两次,两个或更多实例. 有想法吗?
I have a CherryPy server running on a BeagleBone Black. Server generates a simple webpage and does local SPI reads / writes (hardware interface). The application is going to be used on a local network with 1-2 clients at a time. I need to prevent a CherryPy class function being called twice, two or more instances before it completes. Thoughts?
推荐答案
这是一般的同步问题,尽管 CherryPy 方面有些微妙. CherryPy 是线程服务器,因此拥有应用程序级别的锁定就足够了,例如threading.Lock
.
It is general synchronization question, though CherryPy side has a subtlety. CherryPy is a threaded-server so it is sufficient to have an application level lock, e.g. threading.Lock
.
The subtlety is that you can't see the run-or-fail behaviour from within a single browser because of pipelining, Keep-Alive or caching. Which one it is is hard to guess as the behaviour varies in Chromium and Firefox. As far as I can see CherryPy will try to serialize processing of request coming from single TCP connection, which effectively results in subsequent requests waiting for active request in a queue. With some trial-and-error I've found that adding cache-prevention token leads to the desired behaviour (even though Chromium still sends Connection: keep-alive
for XHR where Firefox does not).
如果单个浏览器中的运行或失败对您而言并不重要,则可以放心地忽略上一个段落,并在下面的示例中忽略 JavaScript 代码.
If run-or-fail in single browser isn't important to you you can safely ignore the previous paragraph and JavaScript code in the following example.
从一个浏览器到同一URL的请求序列化的原因不在服务器端.这是浏览器缓存的实现细节(详细信息).但是,添加随机查询字符串参数nc
的解决方案是正确的.
The cause of request serialisation coming from one browser to the same URL doesn't lie in server-side. It's an implementation detail of a browser cache (details). Though, the solution of adding random query string parameter, nc
, is correct.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import threading
import time
import cherrypy
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8
}
}
class App:
lock = threading.Lock()
@cherrypy.expose
def index(self):
return '''<!DOCTYPE html>
<html>
<head>
<title>Lock demo</title>
<script type='text/javascript' src='http://cdnjs.cloudflare.com/ajax/libs/qooxdoo/3.5.1/q.min.js'></script>
<script type='text/javascript'>
function runTask(wait)
{
var url = (wait ? '/runOrWait' : '/runOrFail') + '?nc=' + Date.now();
var xhr = q.io.xhr(url);
xhr.on('loadend', function(xhr)
{
if(xhr.status == 200)
{
console.log('success', xhr.responseText)
}
else if(xhr.status == 503)
{
console.log('busy');
}
});
xhr.send();
}
q.ready(function()
{
q('p a').on('click', function(event)
{
event.preventDefault();
var wait = parseInt(q(event.getTarget()).getData('wait'));
runTask(wait);
});
});
</script>
</head>
<body>
<p><a href='#' data-wait='0'>Run or fail</a></p>
<p><a href='#' data-wait='1'>Run or wait</a></p>
</body>
</html>
'''
def calculate(self):
time.sleep(8)
return 'Long task result'
@cherrypy.expose
def runOrWait(self, **kwargs):
self.lock.acquire()
try:
return self.calculate()
finally:
self.lock.release()
@cherrypy.expose
def runOrFail(self, **kwargs):
locked = self.lock.acquire(False)
if not locked:
raise cherrypy.HTTPError(503, 'Task is already running')
else:
try:
return self.calculate()
finally:
self.lock.release()
if __name__ == '__main__':
cherrypy.quickstart(App(), '/', config)
这篇关于限制CherryPy中的并行进程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!