如何为类提供类似 with 语句的功能?

发布于 2024-12-17 10:26:20 字数 1041 浏览 4 评论 0原文

[我对这个不恰当的标题表示歉意;我想不出更好的办法了。欢迎提出更好标题的建议。]

我想实现一个支持多进程的 HDF5 文件的接口 -通过文件锁定级别并发。该模块的预期环境是通过 NFS 访问共享磁盘的 Linux 集群。目标是通过在多个不同主机上运行的多个并行进程实现对同一文件的并发访问(通过 NFS)。

我希望能够通过 h5py.File 类的包装类来实现锁定功能。 (h5py 已提供对线程的支持 级并发,但底层 HDF5 库不是线程安全的。)

如果我能本着这个精神做一些事情,那就太好了:

class LockedH5File(object):
    def __init__(self, path, ...):
        ...
        with h5py.File(path, 'r+') as h5handle:
            fcntl.flock(fcntl.LOCK_EX)
            yield h5handle
        # (method returns)

我意识到上面的代码是错误的,但我希望它传达了主要思想:即有这样的表达LockedH5File('/path/to/file') 向客户端代码传递一个打开句柄,然后客户端代码可以对其执行各种任意读/写操作。当该句柄超出范围时,其析构函数将关闭该句柄,从而释放锁。

推动这种安排的目标有两个:

  1. 将句柄的创建(由库代码)与随后在句柄上请求的操作(由客户端代码)分离,

  2. 确保句柄是关闭并释放锁,无论期间发生什么 执行中间代码(例如异常、未处理的 信号,Python 内部错误)。

在Python中怎样才能达到这样的效果呢?

谢谢!

[I apologize for the inept title; I could not come up with anything better. Suggestions for a better title are welcome.]

I want to implement an interface to HDF5 files that supports multiprocess-level concurrency through file-locking. The intended environment for this module is a Linux cluster accessing a shared disk over NFS. The goal is to enable the concurrent access (over NFS) to the same file by multiple parallel processes running on several different hosts.

I would like to be able to implement the locking functionality through a wrapper class for the h5py.File class. (h5py already offers support for thread-level concurrency, but the underlying HDF5 library is not thread-safe.)

It would be great if I could do something in the spirit of this:

class LockedH5File(object):
    def __init__(self, path, ...):
        ...
        with h5py.File(path, 'r+') as h5handle:
            fcntl.flock(fcntl.LOCK_EX)
            yield h5handle
        # (method returns)

I realize that the above code is wrong, but I hope it conveys the main idea: namely, to have the expression LockedH5File('/path/to/file') deliver an open handle to the client code, which can then perform various arbitrary read/write operations on it. When this handle goes out of scope, its destructor closes the handle, thereby releasing the lock.

The goal that motivates this arrangement is two-fold:

  1. decouple the creation of the handle (by the library code) from the operations that are subsequently requested on the handle (by the client code), and

  2. ensure that the handle is closed and the lock released, no matter what happens during the
    execution of the intervening code (e.g. exceptions, unhandled
    signals, Python internal errors).

How can I achieve this effect in Python?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦里梦着梦中梦 2024-12-24 10:26:20

可以在 with 语句中使用的对象称为上下文管理器;他们实现了一个简单的界面。它们必须提供两个方法,一个 __enter__ 方法,该方法不带任何参数,并且可以返回任何内容(将被分配给 as 部分中的变量),以及一个 >__exit__ 方法,它接受三个参数(将用 sys.exc_info() 的结果填充)并返回非零以指示异常已被处理。您的示例可能如下所示:

class LockedH5File(object):
    def __init__(self, path, ...):
        self.path = path

    def __enter__(self):
        self.h5handle = h5handle = h5py.File(self.path, 'r+')
        fcntl.flock(fcntl.LOCK_EX)
        return h5handle

    def __exit__(self, exc_type, exc_info, exc_tb):
        self.h5handle.close()

objects that can be used in with statements are called context managers; and they implement a simple interface. They must provide two methods, an __enter__ method, which takes no arguments and may return anything (which will be assigned to the variable in the as portion), and an __exit__ method, which takes three arguments (which will be filled in with the result of sys.exc_info()) and returns non-zero to indicate that an exception was handled. Your example will probably look like:

class LockedH5File(object):
    def __init__(self, path, ...):
        self.path = path

    def __enter__(self):
        self.h5handle = h5handle = h5py.File(self.path, 'r+')
        fcntl.flock(fcntl.LOCK_EX)
        return h5handle

    def __exit__(self, exc_type, exc_info, exc_tb):
        self.h5handle.close()
唔猫 2024-12-24 10:26:20

要实现此功能,您的类需要实现上下文管理器协议。或者,使用 contextlib.contextmanager 装饰器编写生成器函数。

您的类可能大致如下所示(h5py 用法的详细信息可能是严重错误的):

class LockedH5File(object):
    def __init__(self, path, ...):
        self.h5file = h5py.File(path, 'r+')
    def __enter__(self):
        fcntl.flock(fcntl.LOCK_EX)
        return self.h5file
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.h5file.close()

To make this work, your class needs to implement the context manager protocol. Alternatively, write a generator function using the contextlib.contextmanager decorator.

Your class might roughly look like this (the details of h5py usage are probably horribly wrong):

class LockedH5File(object):
    def __init__(self, path, ...):
        self.h5file = h5py.File(path, 'r+')
    def __enter__(self):
        fcntl.flock(fcntl.LOCK_EX)
        return self.h5file
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.h5file.close()
你与昨日 2024-12-24 10:26:20

嗯,一个上下文管理器和 with 语句。一般来说,Python 中的析构函数根本不能保证运行,因此除了故障安全清理之外,您不应该依赖它们。提供__enter____exit__方法,并像使用它一样

with LockedFile(...) as fp:
    # ...

Well, a context manager and with statement. In general, destructors in Python are not guaranteed to run at all, so you should not rely on them as anything other than fail-safe cleanup. Provide __enter__ and __exit__ methods, and use it like

with LockedFile(...) as fp:
    # ...
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文