【问题标题】:Celery + Redis for multiprocessing用于多处理的 Celery + Redis
【发布时间】:2021-04-23 20:37:28
【问题描述】:

我使用 tesseract、openCV 和 Google Vision 构建了一个用于光学字符识别的应用程序。 我有 4 种可用的文件类型可供识别(如收据)。因此用户可以选择文件(图像),然后选择文档的确切类型并单击“识别”。会发生这样一个过程:

  1. 使用 openCV 进行图像对齐: 我们有每种文档类型的示例图像。例如,当用户选择类型 A 时,openCV 会找到类型 A 的示例图像并开始搜索相似性。当找到足够多的相似元素时,openCV 会对齐用户的图像文件以达到最大相似度。 函数结果 - 返回对齐图像的路径。
  2. 使用 tesseract 进行验证: 对齐之后,tesseract 打开之前对齐的图像并识别它。然后我有一个单词列表,它必须在可识别的文本中,因此我们开始检查已识别的文本,并且对于每个成功的置信度我们增加我们的验证计数器。所以最后,如果我们的验证计数器 > 一定数量,我们批准结果并认为图像文件是正确的,可以在下一步被谷歌识别。如果验证计数器不足以批准,我们将文档类型设置为 None 对象。 函数结果 - 返回批准的对齐图像的路径和用户在开始时选择的文档类型。
  3. 在此之后我们启动最终功能。如果文档类型不是无(这意味着我们有一个已批准的图像文件),我们将此图像路径传递给将使用 Google Vision API 进行识别的函数,然后我们会得到一个 .txt 文件。

所以这是常见的情况。但我也提供用户选择文档的类型,称为“我不知道类型”;) 选择这种类型后执行的函数只是通过 for 循环(迭代我们拥有的所有文档类型)。因此,当我们每次使用 openCV+Tesseract 完成工作时都返回我们的文档类型,很明显我们只会得到一个非 None 类型,这将是正确的,我们将使用它来识别。 所以这个函数的执行时间最长,因为我们需要做最多 4 次 openCV 对齐和最多 4 次 tesseract 识别才能找到合适的文档类型。 我想通过为这个特定功能实现多处理来加速我的程序。我决定为这些目的使用 Celery+Redis。 这个想法是:

  1. 将此循环函数设置为 Celery 任务。
  2. 等待所有操作完成。
  3. 从redis读取响应(必须有4个响应,其中3个是NoneType,1个是真实的Document Type)。
  4. 清理 redis。
  5. 在最终的 Google 函数中使用正确的类型。

所以这些是我的功能,我在上面说过:

raw_img_path - 用户使用 UI 选择的路径 dt - 用户使用 UI 选择的文档类型

calc_receipt - 用于识别我们何时知道文档类型:

def calc_receipt(self, raw_img_path, dt):
    aligned_img_path = OpenCV.align_img(
        template_path="some\\path\\for\\chosen\\type",
        raw_img_path="user\\image\\path",
        result_img_path="aligned\\image\\path",
    )

    tesseract_result = Tesseract.read_from_img(
        img_path="aligned\\image\\path",
    )

    if tesseract_result:
        return aligned_img_path, dt

    return '', DocumentType.NONE

calc_receipts - 用于在我们不知道类型时进行识别:

def calc_receipts(self, raw_img_path, selected_doc_type):

    for dt in map_receipt_to_receipts[selected_doc_type]:
        aligned_img_path, doc_type = self.calc_receipt(raw_img_path, dt)
        if doc_type is not DocumentType.NONE:
            return aligned_img_path, doc_type

可用类型列表:

map_receipt_to_receipts = {
    DocumentType.NONE: [],
    DocumentType.DONT_KNOW: [
        DocumentType.RESTAURANT,
        DocumentType.CAFE,
        DocumentType.BAR,
        DocumentType.COFFEE_SHOP,
    ],
    DocumentType.RESTAURANT: [
        DocumentType.RESTAURANT,
    ],
    DocumentType.CAFE: [
        DocumentType.CAFE,
    ],
    DocumentType.BAR: [
        DocumentType.BAR,
    ],
    DocumentType.COFFEE_SHOP: [
        DocumentType.COFFEE_SHOP,
    ],
}

类 DocumentType 是为了方便而制作的:

class DocumentType(EnumBase):
    NONE = 0
    DONT_KNOW = 1
    RESTAURANT = 2
    CAFE = 3
    BAR = 4
    COFFEE_SHOP = 5

据我所知,我需要重建 calc_receipts() 函数。我有一些问题:

  1. 我应该从这个函数启动 celery worker 吗?
  2. 我可以从 Python 代码而不是使用控制台启动 celery 客户端吗?
  3. 如何管理 redis 响应并等待所有 4 个操作。
  4. 对于这种使用 Celery+Redis 的案例,您通常会推荐什么? 如果我的问题很愚蠢,我很抱歉,但我很难在网上找到答案。文档不够清晰,对初学者不够友好。

【问题讨论】:

    标签: python redis celery


    【解决方案1】:

    A1:Celery worker 作为一个独立的进程启动。是的,您可以以编程方式启动它,但这非常罕见(我使用它近 6 年,从未需要它)。我想一旦你熟悉了 Celery,你就会发现什么是最适合你的。直到你发现你真的需要以这种方式启动它,我建议将它作为一个独立的进程运行。在生产中,您可能希望它作为系统服务。

    A2:老实说,没有“celery 客户端”之类的东西……Celery 建立在受支持的代理提供的消息传递功能之上。根据分布式生产者/消费者(或发布/订阅)模式来考虑它。如果“客户端”的意思是“生产者” - 将消息(任务)发送到特定队列(或使用最常见的默认队列)的东西,那么是的,你可以通过编程方式做到这一点,事实上这就是我们大多数人都在这样做。

    A3:你不关心 Redis。这完全是 Celery 的工作。如果我理解你,你需要构建一个简单的工作流,可能使用 Chord 原语(因为你需要等到所有任务都完成)。为此,您需要熟悉Celery workflows

    A4:我使用 Celery 和 Redis(实际上是 AWS ElastiCache)作为代理和结果后端。我相信 Redis 可能是 Celery 最常用的代理,可能是因为它的设置和使用非常简单。 Celery 文档可能看起来不清楚,但它包含大量信息。此外,您还有数以千计的博客,其中包含描述人们如何在各种情况下使用 Celery 的文章。像往常一样,从简单的事情开始,少做工人,然后尝试以分布式方式执行一些小任务。我是按照First steps with Celery文档学习Celery的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-25
      • 2015-06-25
      • 2014-06-06
      • 1970-01-01
      • 2021-02-12
      • 2018-06-03
      • 2019-11-20
      • 2014-09-20
      相关资源
      最近更新 更多