芹菜可以合作运行协同程序作为有状态/可恢复的任务吗?

时间:2014-10-25 20:15:02

标签: python celery coroutine eventlet

我目前正在调查Celery用于视频处理后端。基本上我的问题如下:

  1. 我有一个前端Web服务器,可同时处理大量视频流(大约数千个)。
  2. 每个流必须独立处理并行
  3. 流处理可分为两种类型的操作:
    1. 逐帧操作(不需要有关前一帧或后一帧信息的计算)
    2. 流级操作(对有序相邻帧的子集起作用的计算)
  4. 鉴于第3点,我需要在整个过程中维护和更新框架的有序结构,并将此结构的子部分的农场计算提供给Celery工作人员。最初,我考虑如下组织事情:

    [frontend server]  -stream-> [celery worker 1 (greenlet)] --> [celery worker 2 (prefork)]
    

    这个想法是celery worker 1执行长期运行的主要是I / O绑定的任务。从本质上讲,这些任务执行以下操作:

    1. 从前端服务器读取一个框架
    2. 从它的base64表示
    3. 解码帧
    4. 将其排入前面提到的有序数据结构(collections.deque对象,如目前所示)。
    5. 任何CPU绑定操作(图像分析)都会发送到celery worker 2

      我的问题如下:

      我想将协程执行为一项任务,以便我可以yield执行长期运行的任务,以便不阻止celery worker 1的操作。换句话说,我希望能够做类似的事情:

      def coroutine(func):
          @wraps(func)
          def start(*args, **kwargs):
              cr = func(*args, **kwargs)
              cr.next()
              return cr
          return start
      
      @coroutine
      def my_taks():
          stream = deque()  # collections.deque
          source = MyAsynchronousInputThingy()  # something i'll make myself, probably using select
      
          while source.open:
              if source.has_data:
                  stream.append(Frame(source.readline()))  # read data, build frame and enqueue to persistent structure
              yield  # cooperatively interrupt so that other tasks can execute
      

      有没有办法让基于协程的任务无限期地运行,理想情况下会产生yield的结果?

1 个答案:

答案 0 :(得分:3)

Eventlet背后的主要思想是你要编写同步代码,就像使用线程一样,socket.recv()应该阻止当前线程直到下一个语句。这种风格在调试时非常容易阅读,维护和推理。为了使事情变得有效和可扩展,在幕后,Eventlet可以用绿色线程和epoll / kqueue / etc机制替换看似阻塞的代码,以便在适当的时间唤醒那些绿色线程。

所以你需要的只是尽快执行eventlet.monkey_patch()(例如模块中的第二行)并确保在MyInputThingy中使用纯Python套接字操作。忘记异步,只需像编写线程一样编写普通的阻塞代码。

Eventlet使同步代码再次良好。