我要么不了解 Python 中的多处理,要么不了解 Flask+SQLAlchemy

I either don't understand multiprocessing in Python or Flask+SQLAlchemy

前段时间我在 Python 3 中编写了一个 Flask 应用程序,它生成一个新线程进行一些处理,然后定期更新应用程序数据库 (SQLite)。我用来更新数据库的函数非常简单:

def update_db(tsid, **kwargs):
    # FLASK_APP is my main Flask() object, set once when thread starts
    # DATABASE is the SQLAlchemy DB connection, set once when thread starts
    # TrainingSession is my custom DB model object (from SQLAlchemy.Model)
    with FLASK_APP.app_context():
        dbrec = TrainingSession.query.filter_by(id=tsid).first()
        if dbrec:
            for key, value in kwargs.items():
                setattr(dbrec, key, value)
            DATABASE.session.commit()

这工作得很好 - 我的线程产生了其他几个线程,每个线程都调用上面的 update_db() 函数,正确更新了数据库。

现在我更改了我的代码,因为我想使用进程而不是线程(这会再次产生其他线程)。所以我只是简单地从 Python multiprocessing.Process 而不是 threading.Thread 继承了我的 class。这个子进程现在完成所有工作 - 而且仍然正确。

很好。但我不明白的是为什么我的数据库更新仍然像以前一样工作,即使我没有改变上面显示的逻辑。全局变量 FLASK_APPDATABASE 在我的主应用程序进程中设置,在新进程启动之前。然后在这个新过程中我仍然像上面那样调用全局函数update_db(),它仍然有效。

首先,另一个进程如何访问这两个全局变量?它们不会从主进程传递到子进程,后者只需访问它们而无需更改代码(因为它们是 Python 脚本中的全局对象)。此外,如果在主进程中创建了 FLASK_APPDATABASE 对象(并且从未传递给子进程),子进程如何访问和更新数据库?

这是因为默认情况下 multiprocessing 使用 fork() 来创建新进程,这意味着包括父进程中的所有变量在内的整个内存状态也存在于子进程中。

如果您将多处理更改为 spawn 模式,您将获得没有任何现有状态的新解释器,您的代码将不再神奇地工作。

文档在 https://docs.python.org/3/library/multiprocessing.html#contexts-and-start-methods

对其进行了解释