【问题标题】:Global variables and MPI全局变量和 MPI
【发布时间】:2012-08-14 11:56:59
【问题描述】:

我知道全局变量是不好的,应该尽量避免。但是,例如在使用 MPI 编写并行程序时,某些变量只会被初始化一次,并且永远不会改变(此任务的数量、任务总数等)。将这些变量作为全局变量仍然被认为是不好的做法吗?由于您几乎总是需要访问这些变量,因此在 main 中为它们创建一个类并将指向它的指针传递给程序中 99% 的函数似乎很愚蠢。到目前为止,我的方法是将它们隐藏在命名空间 mpi_glob 中(对于 C++ 的情况,我想我不会费心将它们放在 C 中的结构中来模拟命名空间)。我想这个问题也适用于其他仅设置一次的变量,例如单位制等。

【问题讨论】:

    标签: c++ c global-variables mpi


    【解决方案1】:

    全局变量“不好”的原因是它们在难以识别和跟踪的单独源文件之间引入了耦合。尤其是,如果全局变量在程序中的某个时刻出现意外状态,则很难弄清楚它是在哪里修改的。

    将全局变量替换为通过引用传递给程序中每个函数的局部变量并不能消除这个问题。用设计术语来说,它是“流浪数据”,即即使在不需要的地方也会四处游荡的数据。

    现在,这里的重点是,正如您所建议的,初始化一次且从未更改过的数据不存在使全局变量“坏”的问题。由于问题不存在,因此不需要解决方案。

    【讨论】:

      【解决方案2】:

      不应该遵循任何规则越过悬崖,具体情况完全取决于您编写的程序类型。

      如果您的程序相对较小(或者您是唯一一个编写/维护它的人),那么将“全局”变量留在一个特殊的命名空间中可能没问题。至少这样你就不会在某个地方的本地范围内意外地对它们进行阴影或踩踏。这是假设你没有做这样的事情:

      using namespace mpi_glob;
      

      这与仅将全局变量放在某个文件中并不能很好地保护它们几乎没有什么不同。

      如果它通过使用全局变量使你的程序更清晰和易于理解,那么就使用它们。如果可以将它们保留在本地,请将它们保留在本地,因为从长远来看,这通常会使维护变得更简单。

      【讨论】:

        【解决方案3】:

        我想Singleton 应该可以帮助您更好地管理它,因此您不必传递指针。实际上,mpi_glob 也是如此,Singleton 只是更习惯的方式。

        或者,您仍然可以使用全局变量——它们本身也不错。如果你想强调一次性赋值,你可以声明它们 const 并通过静态初始化器设置它们,如下所示:

        const int number_of_tasks = get_preconfigured_number_of_tasks();
        

        如果您的全局变量用于保存编译时常量,那么将它们替换为enum 成员或预处理器定义是完全可以的。这样做会减轻编译器的负担,因为它可以在不访问内存的情况下就地使用立即值。


        感谢 Pete Becker 在评论中指出 Singleton 问题。如果这些问题也困扰您,那么可以采取完全不同的方法。

        还记得 Java 程序是如何实现的吗?有一个带有主方法的主类,所有程序的工作都在该主方法中运行。 Main 仍然是成员函数,即它可以独占访问主类的一些私有字段(在 Java 的情况下它们必须是静态的,但这不是这里的重点)。

        我们可以将概念进一步扩展到Command-like 实现。与传统 Java 的不同之处在于您的 main 等效方法不是静态的,并且具有特定于包含程序的值的全局变量是非静态成员变量。所有需要访问全局状态数据的函数都将转换为成员函数。这是可能的,因为 main 方法也是成员函数。

        我认为这样可以实现更好的封装性和数据安全性。

        【讨论】:

        • 单例对于常量来说太过分了,并且只为全局数据提供了安全的假象。全局数据的问题在于它可以从任何源文件中修改,因此很难看出在哪里进行了特定的更改。使其成为单例并不会改变这一点。我知道使用单例的唯一好处是它减少了初始化问题的顺序。但是初始化顺序问题是由于过度使用全局变量引起的;减少全局变量的使用也减少了这些问题,并减少了全局变量存在的调试问题。
        • @PeteBecker 我同意你关于数据控制的观点,特别是如果单例只是一个没有 getter/setter 的哑对象。在这种情况下,单例并不意味着带来 OP 没有要求的优势。我画它只是为了代表像我这样的普通程序员所期望的更普通的方式。对于常量来说,这肯定是一种矫枉过正,这就是为什么还有其他选择。
        • 从单例中获得的对象是否具有 getter 和 setter 并不重要。它仍然是全球数据。 getter 和 setter 与仅使用简单的全局数据一样有用,也同样有用。
        猜你喜欢
        • 2013-12-29
        • 1970-01-01
        • 2013-05-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-14
        • 1970-01-01
        • 2022-01-28
        相关资源
        最近更新 更多