限制CherryPy中的并行进程?

时间:2014-10-14 20:19:39

标签: cherrypy beagleboneblack

我有一个在BeagleBone Black上运行的CherryPy服务器。服务器生成一个简单的网页,并进行本地SPI读/写(硬件接口)。该应用程序将在具有1-2个客户端的本地网络上一次使用。 我需要阻止CherryPy类函数在完成之前被调用两次,两次或多次实例。 想法?

2 个答案:

答案 0 :(得分:0)

这是一般同步问题,虽然 CherryPy 方面有一个微妙之处。 CherryPy 是一个线程服务器,因此只需要一个应用程序级锁即可。 threading.Lock

微妙之处在于,由于流水线操作,Keep-Alive或缓存,您无法在单个浏览器中看到运行或失败行为。由于Chromium和Firefox中的行为不同,很难猜到哪一个。据我所知, CherryPy 将尝试序列化来自单个 TCP 连接的请求处理,这有效地导致后续请求等待队列中的活动请求。通过一些反复试验,我发现添加缓存预防令牌会导致所需的行为(即使Chromium仍然为XHR发送Connection: keep-alive,而Firefox却没有)。

如果单个浏览器中的 run-or-fail 对您来说并不重要,您可以放心地忽略上一段和 JavaScript 代码。< / p>

更新

从一个浏览器到同一个URL的请求序列化的原因并不在于服务器端。它是浏览器缓存(details)的实现细节。但是,添加随机查询字符串参数nc的解决方案是正确的。

#!/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)

答案 1 :(得分:0)

正如saaj所评论的,一个简单的threading.Lock()将阻止处理程序由另一个客户端同时运行。我还可以补充一点,using cherrypy.session.acquire_lock()会阻止同一个客户端同时运行两个处理程序。

关于Python锁和东西的更新文章:http://effbot.org/zone/thread-synchronization.htm

虽然通过使用&#34;和#34;我会使saaj的解决方案变得更加简单。 Python中的语句,隐藏所有那些花哨的锁定获取/释放和try / except块。

lock = threading.Lock()

@cherrypy.expose
def index(self):
    with lock:
        # do stuff in the handler.
        # this code will only be run by one client at a time
        return '<html></html>'