【问题标题】:Python synchronise between threads and processesPython在线程和进程之间同步
【发布时间】:2014-11-02 05:49:09
【问题描述】:

一点背景:

我在 Django 中写了一个函数来获取下一个发票号码,它需要是连续的(不是间隙),所以函数看起来像这样:

def get_next_invoice_number():
    """
    Returns the max(invoice_number) + 1 from the payment records
    Does NOT pre-allocate number
    """
    # TODO ensure this is thread safe
    max_num = Payment.objects.aggregate(Max('invoice_number'))['invoice_number__max']
    if max_num is not None:
        return max_num + 1
    return PaymentConfig.min_invoice_number

现在的问题是,这个函数只返回max()+1,在我的生产环境中我有多个 Django 进程,所以如果这个函数被调用两次以进行 2 次不同的付款(在保存第一条记录之前),他们将得到相同的发票号码。

为了缓解这个问题,我可以重写 save() 函数来调用 get_next_invoice_number() 以最小化这些函数调用之间的时间间隔,但问题发生的可能性仍然很小。

所以我想在approve方法中实现一个锁,比如

from multiprocessing import Lock
lock = Lock()

class Payment(models.Model):
    def approve(self):
        lock.acquire()
        try:
            self.invoice_number = get_next_invoice_number()
            self.save()
        except: 
            pass
        finally:
            lock.release()

所以我的问题是:

  1. 这看起来还可以吗?
  2. 锁是多进程的,线程呢?

更新:

  1. 正如我的同事所指出的,当它部署到多个服务器时,这将不起作用,锁定将毫无意义。
  2. 看起来 DB 事务锁定是可行的方法。

【问题讨论】:

  • 1.) 为什么需要顺序? 2.) 为什么不能在支票上预先分配发票 ID(即使用数据库的自动增量功能)?这样就不会重复了。
  • @Andy 这是一个商业会计要求发票编号是连续的。

标签: python django multithreading locking multiprocessing


【解决方案1】:

到目前为止,最简单的方法是使用数据库中用于创建序列的现有工具。事实上,如果你不介意从1 开始的值,你可以使用Django 的AutoField

如果您的业务要求需要选择起始编号,则必须查看如何在数据库中执行此操作。这里是 some questions 可能会有所帮助。

尝试使用锁或事务来确保这一点将更难执行且执行速度更慢。

【讨论】:

    最近更新 更多