我是python的新手,目前正在尝试学习线程.我厌倦了使用锁来使我的资源成为线程安全的,因为它们本身并不依赖于资源,所以每次我的代码与资源交互时,我都会忘记获取和/或释放它们.相反,我希望能够"包装"(或装饰?)一个对象,以便它的所有方法和属性getter/setter都是原子的.这样的事情:
state = atomicObject(dict())
# the following is atomic/thread-safe
state["some key"] = "some value"
Run Code Online (Sandbox Code Playgroud)
这可能吗?如果是这样,那么实施它的"最佳实践"方式是什么?
编辑:如何使内置容器(集,dicts,列表)线程安全可用的上述问题的一个很好的答案?.然而; 正如abarnert和jsbueno都证明的那样,我提出的解决方案(自动锁定)通常不是一个好主意,因为确定原子操作的适当粒度需要一些智能,并且可能很难(或不可能)正确自动化.
问题仍然存在,锁不以任何方式绑定到它们要保护的资源,因此我的新问题是:将锁与对象关联起来的好方法是什么?
提出的解决方案#2:我想可能有一种方法可以将锁绑定到一个对象,这样在没有首先获取锁的情况下尝试访问该对象会引发错误,但我可以看到这可能会变得棘手.
编辑:以下代码与问题无关.我发布它是为了证明我曾尝试自己解决问题并在发布此问题之前迷路了.
为了记录,我编写了以下代码,但它不起作用:
import threading
import types
import inspect
class atomicObject(object):
def __init__(self, obj):
self.lock = threading.RLock()
self.obj = obj
# keep track of function handles for lambda functions that will be created
self.funcs = []
# loop through all the attributes of the passed in object
# and create wrapped versions of each attribute …Run Code Online (Sandbox Code Playgroud) 我有一个名为“更新程序”的长期运行进程,它已提交更新(到 ETL 系统)。更新具有通过将上下文管理器添加到更新程序的 ExitStack 来管理的资源要求。某些更新将包括新配置,这意味着必须从堆栈中释放受影响的资源,并且将添加该资源的新配置版本。我需要类似的东西:
with ExitStack() as stack:
ctx_manager = open("file.txt")
f = stack.enter_context(ctx_manager)
...
ctx_pop(ctx_manager, stack) # remove the given context manager from the stack
Run Code Online (Sandbox Code Playgroud)
下面是我已经开始工作的示例,但它依赖于访问受保护的成员。我希望可能有一个比这更“肮脏”的解决方案:
def ctx_pop(cm, stack):
for item in stack._exit_callbacks:
if item.__self__ is cm:
break
else:
raise KeyError(repr(cm))
stack._exit_callbacks.remove(item)
item(None, None, None)
Run Code Online (Sandbox Code Playgroud)
编辑:添加已知解决方案