限制CherryPy中的并行进程? [英] Limit parallel processes in CherryPy?

查看:83
本文介绍了限制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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆