在使用许多进程与数据库交互时,我遇到了一些奇怪的应用程序行为。我在用Linux。在
我有自己的QueryExecutor
实现,它在其生命周期内使用单个连接:
class QueryExecutor(object):
def __init__(self, db_conf):
self._db_config = db_conf
self._conn = self._get_connection()
def execute_query(self, query):
# some code
# some more code
def query_executor():
global _QUERY_EXECUTOR
if _QUERY_EXECUTOR is None:
_QUERY_EXECUTOR = QueryExecutor(some_db_config)
return _QUERY_EXECUTOR
在实例化之后,Query Executor
永远不会被修改。在
最初只有一个进程,它不时地分叉(os.fork()
)几次。新流程是完成某些任务然后退出的工人。每个工作线程调用query_executor()
以执行SQL查询。在
我发现sql查询经常返回错误的结果(似乎有时sql查询结果返回到错误的进程)。唯一合理的解释是所有进程共享同一个sql连接(根据MySQLdb doc:threadsafety=1线程可以共享模块,但连接不共享)。在
我想知道是哪个操作系统机制导致了这种情况。据我所知,在Linux上,当进程分叉时,父进程的页面不会被复制给子进程,而是由两个进程共享,直到其中一个进程试图修改某个页面(copy on write)。如前所述,QueryExecutor
对象在创建后保持不变。我想这就是为什么所有进程都使用相同的QueryExecutor
实例,因此使用相同的sql连接。在
我是对的还是我错过了什么?你有什么建议吗?在
提前谢谢!在
格雷戈尔茨
问题的根源在于
fork()
只是创建一个进程的完全独立副本,但是这两个进程{a1}。这就是为什么MySQL server编写的任何数据都可能[正确地]从单个进程读取,如果两个进程试图发出请求并读取响应,那么它们很可能会使彼此的工作陷入混乱。这与“多线程”没有任何关系,因为在多线程的情况下,只有一个进程执行的线程很少,它们共享数据并可能进行协调。在使用
fork()
的正确方法是在进程的所有副本中分叉所有类似文件句柄的对象之后close(或重新打开),或者至少避免在多个进程中使用它们。在相关问题 更多 >
编程相关推荐