Fortran 中的主机关联与使用关联 [英] Host Association vs Use Association in Fortran

查看:17
本文介绍了Fortran 中的主机关联与使用关联的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有什么一般规则"来说明什么时候一个比另一个更可取?

Are there any "general rules" as to when one is preferable to the other?

这个问题的上下文是:我昨天问了一个关于主机关联的不同问题 (link) 并且在评论中,我被建议谨慎使用主机关联.原因是通过主机关联,很容易无意中修改变量,因为子程序可以不受限制地访问模块中声明的所有变量.

The context of this question is: I asked a different question regarding host association yesterday (link) and in the comments, I was advised to use host association with caution. The reason being that through host association, it is easy to inadvertently modify variables since the subroutines have unrestricted access to all variables that are declared in the module.

为了说明这一点,我将使用以下代码示例:

To illustrate this, I will use the following code example:

module mod
implicit none

real :: x

contains

subroutine sub(y)
  use other_mod, only: a

  real, intent(out) :: y

  y = a + x
  a = a + 1.
  x = x + 1.
end subroutine sub

end module mod

ax都在sub中被修改.但是对于x,我需要遍历所有代码才能看到这一点.通过查看 sub 的声明部分,可以很容易地看出 asub 中使用(并且可能被修改).

Both aand x are modified in sub. But for x, I need to go through all the code to see this. That a is used in sub (and possibly modified) can be seen easily by looking at the declaration part of sub.

从这个意义上说,最好有两种模块:

In this sense, it seems preferable to have two kinds of modules:

  1. 一个或多个仅包含变量声明的模块(然后在需要时使用)
  2. 仅包含过程和可能的参数声明但不包含变量声明的模块

这完全摆脱了变量的主机关联.

This gets rid of host association for variables altogether.

但这似乎不切实际,原因有很多:

But this doesn't seem practical for a number of reasons:

  • 我可能有十几个子程序在一个模块中使用(和修改)相同的变量.每次都必须使用这些变量会使代码变得混乱,尤其是当它们很多(比如几百个)时.
  • 将变量的声明与实际使用的位置分开似乎会使代码更难理解:
    • 要么创建一个包含所有声明的巨大控制文件.如果代码很大并且使用许多变量,这可能会非常混乱.
    • 或者,为每个模块(或模块组,如果它们依赖于相同的内容)创建一个单独的控制文件.这将使代码本身更易于理解,因为使用变量会立即显示它们的来源.但它会使代码结构复杂化,创建一个更加复杂的文件结构(以及伴随的依赖结构).
    • I might have a dozen subroutines using (and modifying) the same variables in one module. Having to use these variables everytime clutters the code, especially if there are a lot of them (say a few hundred).
    • Seperating the declaration of a variable from where it is actually used seems to make the code less comprehensible:
      • Either, one creates one giant control file containing all the declarations. This could be quite confusing if the code is large and uses many variables.
      • Or, one creates a seperate control file for every module (or group of modules, if they depend on the same content). This would make the code itself better comprehensible, since using the variables immediately shows where they are coming from. But it would complicate the structure of the code, creating a vastly more complicated file structure (and accompanying dependency structure).

      最后,所有这一切归结为:什么时候将变量的声明放在使用它们的同一个模块中(以便它们被主机关联使用)以及什么时候更明智将声明外包给单独的模块更明智(以便在需要时通过使用关联使用变量)?

      In the end, all of this boils down to: When is it more sensible to put the declaration of variables in the same module in which they are used (so that they are used by host association) and when is it more sensible to outsource the declaration to a seperate module (so that the variables will be used via use association when they are needed)?

      是否有任何一般准则或应根据具体情况来决定?如果是个案,那么选择一个的原因是什么?

      Are there any general guidelines or should this be decided on a case by case basis? And if it is case by case, what are the reasons to go for one over the other?

      推荐答案

      Fortran 提供了多种方法来创建、存储、使用和在不同程序单元"之间传递数据:主程序、外部过程和模块.1 如您所知,每个程序单元都可以包含内部过程 - 通过主机关联,它们可以访问包含在主机中的任何变量或过程.这通常被视为一种优势.正如@HighPerformanceMark 在他的评论中已经提到的,何时使用主机关联或使用关联的一般准则是:

      Fortran provides several ways to create, store, use, and pass data between different "program units": the main program, external procedures, and modules.1 As you know, each program unit can contain internal procedures - which, through host association, have access to any variable or procedure contained within the host. This is often seen as an advantage. As mentioned already by @HighPerformanceMark in his comment, the general guideline for when to use host-association or use-association is:

      当变量只(或主要)被同一模块中声明的例程使用时使用主机关联,当你想定义要在多个模块中使用的变量时使用使用关联

      use host-association when variables are only (or mainly) used by routines declared in the same module, and use use-association when you want to define variables to be used in many modules

      从您的评论来看,听起来您的主程序中的大部分或所有主变量都被每个内部过程(大约十几个子例程)访问.如果是这种情况,那么主机关联似乎是一个非常合理的选择,并且确实没有必要将参数显式传递给每个子例程.另一方面,如果每个子程序实际上只使用变量的一个子集,那么更明确地了解它可能是合理的.

      From your comments, it sounds like most or all of the host variables in your main program are accessed by each internal procedure (about a dozen or so subroutines). If that's the case, then host-association seems like a very reasonable option, and there's really no need to pass in arguments to each subroutine explicitly. On the other hand, if each subroutine actually uses only a subset of the variables, then it might be reasonable to get more explicit about it.

      和您一样,我通常对在过程中使用未在参数列表中声明的变量感到不舒服.这部分是因为我喜欢 args 列表是如何自我记录的,它帮助我推理代码以及如何在其中操作数据.当与其他工人合作时,或者如果我花了一些时间远离代码并且我对它的记忆已经淡化时,情况更是如此.但是,我发现几乎没有理由完全避免主机关联,只要您了解它的工作原理并制定策略即可.

      Like you, I am generally uncomfortable with using variables within a procedure that haven't been declared in an argument list. This is partly because I like how the list of args is self-documenting, and it helps me to reason about the code and how data is manipulated within it. This is even more true when collaborating with other workers, or if I've spent some time away from the code and my memory of it has faded. However, I've discovered there is little reason to avoid host association altogether, as long as you are aware of how it works and have a strategy.

      事实上,我倾向于经常使用内部过程和主机关联,尤其是对于短函数/子例程.我发现将宿主粗略地视为对象",将其变量视为属性",以及非常类似于对象的方法"来完成工作的任何内部过程会很有帮助.当然,这是在简化事情,但这才是真正的重点.

      In fact, I tend to use internal procedures and host-association quite often, especially for short functions/subroutines. I find it helpful to loosely think of the host as the "object", its variables as "attributes", and any internal procedures very much like the object's "methods" that do the work. Of course, that's simplifying things, but that's really the point.

      对于更复杂的程序,我从主"程序本身减少了主机关联的数量,然后它的存在主要是为了以正确的顺序和上下文调用各种子例程.在这种情况下,我们可以利用use-association,在需要的程序单元内直接选择use模块实体(如过程、变量、类型、参数)他们.我们可以进一步限制对那些使用 only: 需要的模块实体的访问.这有助于可读性,清楚地指示数据流,我发现稍后更新代码更直接.您知道,继承、封装等等……但是 Fortran 风格.这实际上相当不错.

      For more complex programs I reduce the amount of host-association from the "main" program itself, which then exists primarily to call the various subroutines in the proper order and context. In this case, we can take advantage of use-association and choose to use module entities (such as procedures, variables, types, parameters) directly within the program unit that needs them. We can further restrict access to only those module entities that are needed with only:. This aids readability, the data flow is clearly indicated, and I find that updating the code later is more straightforward. You know, inheritance, encapsulation, and whatnot...but Fortran style. Which is actually pretty good.

      这是一个适用于我和我在 Fortran 中从事的中等规模项目的示例程序结构.我喜欢将我广泛使用的(静态)参数保存在一个单独的模块(或多个模块,如果根据功能分组)中.我将派生类型和类型绑定过程保存在另一个单独的模块中.如果有用,我会将某些模块实体设为 private,以便其他程序单元无法访问它们.我想就是这样.

      Here's an example program structure that works for me and the moderately-sized projects I've worked on in Fortran. I like to keep my widely-used (static) parameters in a separate module (or modules, if grouped according to function). I keep derived types and type-bound procedures in another separate module(s). If it's useful, I make certain module entities private, so that they are not accessible from other program units. And I guess that's it.

      module params
          implicit none
          public              !! All items public/accessible by default.
          integer, parameter  :: dp = kind(0.d0)
          integer, parameter  :: nrows = 3
          real(dp), parameter :: one=1.0_dp, two=2.0_dp
          ...
      end module params
      
      module types
          use params, only: dp, nrows
          implicit none
          public              !! Public by default.
          private :: dim2
          ...
          integer, parameter :: dim2 = 3
          ...
          type :: A
              integer :: id
              real(dp), dimension(nrows,dim2) :: data
              contains
              procedure, pass :: init
          end type A
          ...
          contains
          subroutine init(self, ...)
              ...
          end subroutine init
          ...
      end module types
      
      module utils
          implicit none
          private             !! Private by default.
          public :: workSub1, workSub2, subErr
          ...
          integer,save :: count=0 !! Accessible only to entities in this module.
          ...
          contains
          subroutine workSub1(...)
              ...
          end subroutine workSub1
      
          subroutine workSub2(...)
              ...
          end subroutine workSub2
      
          subroutine subErr(...)
              ...
          end subroutine subErr
      
      end module utils
      
      
      program main
          !! An example program structure.
          use params, only: dp
          implicit none
          real(dp) :: xvar, yvar, zvar
          integer  :: n, i
          logical  :: rc
      
          call execute_work_subroutines()
      
          contains                !! Internal procs inherit all vars declared or USEd.
          subroutine execute_work_subroutines()
              use types, only: A
              type(A) :: DataSet
              !! begin
              call DataSet%init(i)
              do i = 1,n
                  call workSub1(xvar,yvar,zvar,A,i,rc)
                  if (rc) call subErr(rc)
                  call workSub2(A,rc)
                  if (rc) call subErr(rc)
              enddo
          end subroutine execute_work_subroutines
      end program main
      

      1也有子模块,但我不熟悉它们,也不想给出误导性的信息.它们似乎对逻辑分离大型模块很有用.

      这篇关于Fortran 中的主机关联与使用关联的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆