【问题标题】:Safe method for updating R packages - is "hot-swapping" possible?更新 R 包的安全方法 - “热交换”可能吗?
【发布时间】:2012-02-10 03:24:01
【问题描述】:

我遇到过几次这个问题,除了小问题(见下文)之外,我无法找到任何解决方案。

假设一台计算机正在运行 2+ 个 R 实例,由于 2+ 个用户或 1 个用户运行多个进程,并且一个实例执行 update.packages()。我有几次其他实例可能会被严重破坏。正在更新的包不会以任何影响计算的方式更改功能,但不知何故会出现一个大问题。

简单的解决方案(解决方案 0)是在 update.packages() 执行时终止所有 R 实例。这有2个以上的问题。首先,必须终止 R 实例。其次,人们甚至可能无法确定这些实例在哪里运行(请参阅更新 1)。

假设正在执行的代码的行为不会改变(例如,软件包更新都是有益的——它们只会修复错误、提高速度、减少 RAM 并授予独角兽),是否有某种方法可以热交换新的对其他进程影响较小的软件包版本?

在 R 之外,我还有两个候选解决方案:

解决方案 1 是使用临时库路径,然后删除旧的旧库并将新库移动到它的位置。这样做的缺点是删除 + 移动可能会导致一段时间内没有可用的内容。

解决方案 2 是使用符号链接指向库(或库层次结构),然后用指向更新包所在的新库的指针覆盖符号链接。这似乎会导致更少的程序包停机时间 - 操作系统覆盖符号链接所需的时间。这样做的缺点是在管理符号链接时需要更加小心,并且是特定于平台的。

我怀疑解决方案 #1 可以通过巧妙地使用 .libPaths() 修改为类似于 #2,但这似乎需要调用 update.packages() 而是编写一个新的updater 找到过时的包,将它们安装到临时库,然后更新库路径。这样做的好处是,可以将现有进程限制为它启动时的.libPaths()(即,更改 R 知道的库路径可能不会传播到那些已经在运行的实例,而无需对该实例进行一些显式干预)。


更新 1. 在示例场景中,两个竞争的 R 实例位于同一台机器上。这不是必需的:据我了解更新,如果两者共享相同的库,即共享驱动器上的相同目录,那么更新仍然会导致问题,即使 R 的另一个实例在另一台机器上.因此,可能会意外杀死一个 R 进程,甚至看不到它。

【问题讨论】:

    标签: r packages updates


    【解决方案1】:

    在生产环境中,您可能希望至少保留两个版本,即当前版本和上一个版本,以便在出现问题时能够快速切换回旧版本。什么都不会被覆盖或删除。对于整个 R 生态系统来说,这样做更容易:你会有几个目录,比如“R-2.14.1-2011-12-22”、“R-2.14.1-2012-01-27”等,每个都包含所有内容(R 可执行文件和所有包)。这些目录永远不会更新:如果需要更新,将创建一个新目录。 (某些文件系统提供“快照”,允许您拥有许多非常相似的目录,而不会过度使用磁盘空间。)

    从一个版本切换到另一个版本可以在用户端完成,当用户启动 R 时,可以通过将 R 可执行文件替换为使用正确版本的脚本,或者将其 PATH 环境变量设置为指向想要的版本。这可确保给定会话始终看到相同版本的所有内容。

    【讨论】:

    • 这是一个很好的建议,无论是恢复/“退出”更改的能力,还是重现结果的能力。我需要多考虑一下传达版本信息的开销。
    • 我认为您在最佳实践方面给出了很好的答案。 Josh 的回答更侧重于为什么没有安全的热插拔方法。根据我选择的他的回答,我想说你的回答说明了为了解决这些问题应该做些什么。
    【解决方案2】:

    我强烈的猜测是没有办法解决这个问题。

    尤其是当一个包包含已编译的代码时,您不能在它正在使用时删除和替换 DLL 并期望它仍然可以工作。 R 调用这些函数所使用的所有指向 DLL 的指针都将请求特定的内存位置,然后发现它莫名其妙地消失了。 (注意——虽然我在这里使用术语“DLL”,但我指的是非 Windows 特定的意义,因为它被使用,例如,在?getLoadedDLLs 的帮助文件中。“共享库”可能更好通用术语。)

    (对我的怀疑的一些确认来自the R for Windows FAQ,它报告说“Windows 在加载时锁定[a] 包的DLL”,这可能导致update.packages() 失败。)

    我不确定 R 的延迟加载机制究竟是如何实现的,但想象一下,它也可能因删除它希望在机器中的特定地址找到的对象而被弄乱。

    其他更了解计算机内部的人肯定会给出比这更好的答案,但这是我的想法。

    【讨论】:

    • 这是很重要的一点。我怀疑共享库的问题是跨操作系统的问题。对于大多数用法,我倾向于相信这会扼杀热插拔的想法。最窄的情况是不使用外部共享库的包,但我不确定这对于完全在 R 中的包是如何工作的。
    • 我认为你的回答基本上粉碎了热插拔的梦想。即使我有一个想要热插拔的纯 R 包,假设我可以做到这一点也不是一个好习惯。对于如何进行版本控制而不是交换,Vincent 给出了一个合理的答案,我将不得不进行相当多的调整,但很明显,这是解决您指出的冲突的唯一方法。
    【解决方案3】:

    这是我昨天在 Windows 7 上遇到的一个场景。

    1. 我正在运行 R 会话。
    2. 打开包装手册的 PDF。
    3. 关闭所有 R 会话。忘记关闭包装手册 PDF。
    4. 打开一个新的 R 实例,运行 update.packages()

    安装当然会失败,因为 Windows 仍然打开 pdf 并且无法覆盖它....

    【讨论】:

    • +1 这在共享环境中会很糟糕。我还没有在 Linux 下对多个用户进行测试,但我想知道如果有 100 个用户并且有人正在阅读包小插图,这将如何工作......
    • 在 Linux 上,这不会造成任何问题:默认情况下,正在使用的文件不会被锁定。如果更新后 PDF 文件仍然存在,PDF 查看器会注意到更改、刷新并显示新文件。如果 PDF 文件不再存在,PDF 查看器可能会继续显示旧文件(文件并没有真正删除,它处于不确定状态,仍然存在,没有名称,并且只有在所有应用程序时才会真正消失阅读它关闭文件)。在最坏的情况下,PDF 查看器会显示一条错误消息——但它不会阻止更新。
    猜你喜欢
    • 1970-01-01
    • 2021-04-03
    • 1970-01-01
    • 1970-01-01
    • 2015-11-30
    • 2012-04-26
    相关资源
    最近更新 更多