Python 多线程

2 投票
1 回答
1652 浏览
提问于 2025-04-16 20:13

我有这样的一个情况:

我用Zope/Plone创建了一个网页,还有一些我自己的Python API。这个网页我们叫它“a”,它通过一个Python方法去调用数据库(Postgres),然后返回一些信息。在页面“a”上,你可以“离线”修改数据库的数据(我的意思是这些修改不会立刻写入数据库,而是在你按下“保存”并调用一个Python API方法时才会写入)。想象一下这个场景:一个用户,叫“Sam”,加载了这个页面并开始修改数据。与此同时,另一个用户,叫“Sara”,通过页面“a”点击“保存”来修改数据库。现在Sam没有最新的数据库数据:他按下“保存”后会覆盖Sara的修改。

我想在我的页面上实时显示一个警告。我想我可以这样做:

发起一个AJAX请求,这个请求不会被阻塞,页面可以继续渲染。这个AJAX请求会调用一个Python方法,创建一个线程,这个线程会在一个“X”条件下无限循环。当我在数据库中写入数据时,我会调用一个函数来改变“X条件”,停止这个线程,并返回给AJAX。

而且,我不能锁住数据库,因为我需要让每个想要修改数据库的用户都能自由访问。

我的问题是:我该如何识别一个Python线程?我看到每个从Thread类继承的方法都需要“self”作为参数。此外,我必须在访问“a”页面时调用这个线程,而这段代码会在某个地方(比如在“threads模块”中),但插入操作是在另一个模块中。那么,我该如何实现我的想法呢?

如果有人有其他的想法,请随时告诉我 :)

1 个回答

3

你提到的问题通常被称为“并发”。因为你的方法会在目标项目的任何字段发生变化时警告或阻止用户更新,所以这种方式通常叫做“悲观并发”。一种实现方法是记录下你选择的项目在被选中时的样子,只有当数据库中的版本和你选择的版本完全一致,或者自某个时间点后没有更新时,才进行更新(这时可以用一个时间戳字段来帮助判断)。你也可以尝试“乐观并发”,这种方式是只检查一个用户更新并准备保存到数据库的字段,确保这些字段没有被其他用户更新。这两种方法如果选择一个支持并发的ORM库会更简单。

我最喜欢的Python网页库是Django,这里有一个关于你想解决的相同情况的问题:Django:如何防止数据库条目的并发修改。希望这对你有帮助。

你建议的处理并发的方法是可行的,但在大多数情况下应该避免。我之前在一个大型系统中添加并发时做过类似的事情,那时系统很复杂,涉及的对象有很多副作用,而且没有统一的数据访问(在系统的生命周期中大约有5种数据访问方式,真是五花八门)。这种处理并发的方法容易出错且复杂(我记得我有一个客户端应用,在标记项目为“已借出”后启动了一个监视线程,数据表中描述了对象的类型和标识符、借出用户、借出时间以及有效期,以防借出对象的客户端在完成后未能归还)。

如果你坚持不使用ORM,并且希望在项目发生变化时向用户显示消息,可以尝试使用最后更新时间戳列,让你的ajax调用检查最后更新时间是否大于你第一次加载项目时的时间。因此,如果你要编写一个通用的方法,你只需要表名、主键和时间戳。

webservice方法可能看起来像:

def is_most_current(table_name, id):
    db = MySQLdb.connect(passwd="moonpie",db="thangs")
    c=db.cursor()
    c.execute("SELECT last_updated from %s where id = %s", (table_name, id))
    return c.fetchone()

至于Python的多线程库,Python的线程比较复杂,性能也不好,因为Python有全局锁的问题。在很多情况下,你可能更想启动一个新进程(多进程库在并行处理场景下表现更好)。至于“self”,这是Python中对你正在处理的类实例的引用,类似于C语言中的“this”。你可以在构造线程时给它一个唯一的名字,以便轻松识别。有关更多信息,请查看多进程线程的文档。如果可以避免在这个问题上使用线程,我建议你这样做。

撰写回答