【问题标题】:Is this a thread-safe module, and actually how do you write one?这是一个线程安全的模块,实际上你是怎么写的?
【发布时间】:2012-05-12 18:30:47
【问题描述】:

我实际上正在使用一个涉及大量 mysql 操作的多线程程序,基本上这很痛苦,因为你必须想出一个聪明的方法来使所有查询工作。这让我想到如何使模块线程安全。

无论如何,我试图以这种方式提出我的问题:假设您需要不断地将新内容附加到具有许多不同线程的 txt 文件中,main.py 肯定会如下工作:

import threading

lock = threading.RLock()

def AppendStr(the_str):
    write_thread = threading.Thread(target = RealAppending, args = (the_str, ))
    write_thread.start()

def RealAppending(the_str):
    lock.acquire()

    the_file = open("test.txt", "a")
    the_file.append(the_str)
    the_file.close()

    lock.release()

def WorkerThread(some_arg):
    do stuff

    AppendStr("whatever you like")

for counter in range(100):
    new_thread = threading.Thread(target = WorkerThread, args = (some_arg, ))
    new_thread.start()

好吧,问题是,如果我想让代码整洁且更易于维护,如果我将下面的代码放入 write.py:

是否仍然有效
import threading

lock = threading.RLock()

def AppendStr(the_str):
    write_thread = threading.Thread(target = RealAppending, args = (the_str, ))
    write_thread.start()

def RealAppending(the_str):
    lock.acquire()

    the_file = open("test.txt", "a")
    the_file.append(the_str)
    the_file.close()

    lock.release()

并在 main.py 中这样做:(我不太明白 import 在 python 中的工作原理)

import write

def WorkerThread(some_arg):
    do stuff

    write.AppendStr("whatever you like")

for counter in range(100):
    new_thread = threading.Thread(target = WorkerThread, args = (some_arg, ))
    new_thread.start()

如果有很多其他模块以多线程方式使用write.py,然后您将这些模块导入main.py 并从那里调用不同的def,该怎么办。一切都会按预期进行吗?如果没有,我应该怎么做才能设计一个可以像这样使用的终极线程安全模块?

如果你的write.py 被导入到许多其他模块中,它们是否都共享相同的lock?这些模块中变量的范围是什么?

【问题讨论】:

    标签: python multithreading


    【解决方案1】:

    这看起来像一个线程保存模块,但有错误:

    这是一个更好的版本:

    def RealAppending(the_str):
        lock.acquire()
        try:
            the_file = open("test.txt", "a")
            try:
                the_file.write(the_str) # write
            finally:
                the_file.close()
        finally: # if an error occurs
            lock.release()
    

    因为:

    • 如果写入文件时发生错误,则必须释放锁

    以上语法适用于 python 2.3 及更低版本

    这是完全相同的改进版本:

    def RealAppending(the_str):
        with lock:
            with open("test.txt", "a") as the_file:
                the_file.write(the_str) # write
    

    所以是的,您的模块是线程保存的。 可以添加一些东西来防止用户以非线程保存方式使用它:

    # write.py
    __all__ = ['AppendStr'] # put all functions in except the ones others shall not see
    # so id you do from write import * nothing else will be imported but what is __all__
    

    但您仍然无法知道字符串将以何种顺序写入文件。

    【讨论】:

    • 或者只使用 with 上下文来锁定
    • 如果您从许多不同的其他模块导入此模块,它们是否都共享相同的lock?如果是这样,我想这将是线程安全的,但我只是不确定import 的工作原理以及lock 的范围是什么
    • 如果你将一个函数导入另一个模块,它仍然保留它定义的旧全局变量。如果锁也在另一个模块中也没问题:RealAppending.func_globals 是 write.__dict__
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-10
    • 2015-04-23
    • 2016-08-16
    • 2018-11-07
    • 2023-02-09
    • 1970-01-01
    • 2016-04-28
    相关资源
    最近更新 更多