当前位置: 首页 > 面试题库 >

线程安全和容错文件写入

壤驷阳波
2023-03-14
问题内容

我有一个长时间运行的过程,该过程将很多东西写入文件中。结果应该是全部或什么都没有,因此我正在写入一个临时文件,并在最后将其重命名为真实名称。目前,我的代码是这样的:

filename = 'whatever'
tmpname = 'whatever' + str(time.time())

with open(tmpname, 'wb') as fp:
    fp.write(stuff)
    fp.write(more stuff)

if os.path.exists(filename):
    os.unlink(filename)
os.rename(tmpname, filename)

我对此不满意,原因有几个:

  • 如果发生异常,它将无法正确清理
  • 它忽略了并发问题
  • 它是不可重用的(我在程序的不同位置需要它)

有什么建议可以改善我的代码吗?有图书馆可以帮助我吗?


问题答案:

您可以使用Python的tempfile模块为您提供一个临时文件名。它可以以线程安全的方式创建一个临时文件,而不是使用一个临时文件(time.time()如果同时在多个线程中使用该文件可能返回相同的名称)。

正如对您的问题的评论中所建议的那样,这可以与上下文管理器一起使用。通过查看Pythontempfile.py源代码,您可以得到一些有关如何实现想要执行的操作的想法。

下面的代码段可能会做您想要的。它使用从返回的对象的某些内部tempfile

  • 创建临时文件是线程安全的。
  • 成功完成文件重命名是原子的,至少在Linux上是如此。没有之间的单独检查os.path.exists()os.rename()可能引入竞争状态。对于Linux上的原子重命名,源和目标必须位于同一html" target="_blank">文件系统上,这就是为什么此代码将临时文件与目标文件放置在同一目录中的原因。
  • 在大多数情况下,RenamedTemporaryFile该类的行为应类似于a NamedTemporaryFile,除非使用上下文管理器关闭该类时,文件会重命名。

样品:

import tempfile
import os

class RenamedTemporaryFile(object):
    """
    A temporary file object which will be renamed to the specified
    path on exit.
    """
    def __init__(self, final_path, **kwargs):
        tmpfile_dir = kwargs.pop('dir', None)

        # Put temporary file in the same directory as the location for the
        # final file so that an atomic move into place can occur.

        if tmpfile_dir is None:
            tmpfile_dir = os.path.dirname(final_path)

        self.tmpfile = tempfile.NamedTemporaryFile(dir=tmpfile_dir, **kwargs)
        self.final_path = final_path

    def __getattr__(self, attr):
        """
        Delegate attribute access to the underlying temporary file object.
        """
        return getattr(self.tmpfile, attr)

    def __enter__(self):
        self.tmpfile.__enter__()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type is None:
            self.tmpfile.delete = False
            result = self.tmpfile.__exit__(exc_type, exc_val, exc_tb)
            os.rename(self.tmpfile.name, self.final_path)
        else:
            result = self.tmpfile.__exit__(exc_type, exc_val, exc_tb)

        return result

然后可以像这样使用它:

with RenamedTemporaryFile('whatever') as f:
    f.write('stuff')

在写入过程中,内容进入一个临时文件,退出时该文件被重命名。这段代码可能需要进行一些调整,但是总体思路应该可以帮助您入门。



 类似资料:
  • 问题内容: 我经常听到对Swing库中缺乏线程安全性的批评。但是,我不确定自己将在自己的代码中执行的操作会导致问题: 在什么情况下,Swing不是线程安全的事实起作用? 我应该积极避免做什么? 问题答案: 切勿执行长时间运行的任务以响应按钮,事件等,因为这些事件在事件线程上。如果您阻止事件线程,则整个GUI将完全无响应,从而使用户感到非常生气。这就是为什么Swing看起来缓慢又硬朗。 使用线程,执

  • 该项目是使用Play framework和Scala语言编写的。我已经实现了编译时依赖关系。我在游戏中遵循了以下示例: https://github.com/playframework/play-scala-compile-di-example 查看MyApplicationLoader。scala: 以及以下代码行: 我的理解是,在第一次调用HomeController时,只创建了一个HomeC

  • 问题内容: 假设您有一个用于处理某种XML文件或配置文件的库。该库将整个文件读入内存,并提供用于编辑内容的方法。处理完内容后,可以调用将内容保存回文件。问题是如何以安全的方式执行此操作。 覆盖现有文件(开始写入原始文件)显然是不安全的。如果该方法在完成之前失败,则最终将写入一半的文件,并且您丢失了数据。 更好的选择是在某个位置写入 临时 文件,方法完成后, 将 临时文件 复制 到原始文件。 现在,

  • 问题内容: 我正在寻找关于线程安全信息和。官方文档(http://docs.python.org/library/urllib2.html和http://docs.python.org/library/httplib.html)缺少有关此主题的任何信息。那里甚至没有提到 线程 一词… 更新 好的,它们不是线程安全的。使它们具有线程安全性需要什么,或者存在使它们具有线程安全性的情况?我问是因为好像

  • 问题内容: 在多个类中,是否是线程安全的? 问题答案: 尽管EntityManager实现本身不是线程安全的,但是Java EE容器注入了一个代理,该代理将所有方法调用委托给与事务绑定的EntityManager。因此,每个事务都使用其自己的EntityManager实例。至少对于事务范围的持久性上下文而言,这是正确的(默认设置)。 如果容器将在每个bean中注入EntityManager的新实例

  • 我的Spring项目中有一个简单的: 并按如下方式使用: 我是否必须注意线程安全并使同步(因为不是线程安全的)?我不确定到底是如何工作的--它是否只创建跨所有线程的单个序列化实例?还是为每个转换创建单独的实例?