Python在线程和进程之间进行同步

时间:2014-09-08 22:14:05

标签: python django multithreading locking multiprocessing

一些背景知识:

我正在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. 锁是多进程的,线程怎么样?
  3. 更新

    1. 正如我的同事指出的那样,当它被部署到多个服务器时,这不起作用,锁将毫无意义。
    2. 看起来像DB事务锁定是要走的路。

1 个答案:

答案 0 :(得分:0)

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

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

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