我最近一直在考虑采用传统的建筑分析程序,并为其提供asp.NET Webforms和javascript的前端。 (遗留代码是用Fortran编写的,意图是在Web服务器或其他远程计算机上运行。)
问题:是否可以监控可执行文件的过程(在Web服务器或其他地方运行),以便可以在Webform上报告?
遗留代码仍然是正在进行的开发计划的一部分。我们不打算将其重新编码为C#等,因为:
1)表现至关重要;和
2)这将是一项庞大的事业。
但可以修改Fortran代码以输出内容或调用某些内容来更新进度,并让用户知道(希望通过Webform)可执行文件的工作方式。
有没有人遇到或应用过提供此功能的编程模型?
答案 0 :(得分:1)
FORTRAN程序可以将状态(例如,2015年2月25日12:05:57开始,2015年2月25日12:08:38完成)写入文本文件或数据库表。在状态网页上,您可以使用自动刷新或jQuery ajax调用来检查进程的状态并进行更新。
答案 1 :(得分:1)
我发现在Fortran中执行I / O的最简单方法是使用其原生的.dat文件格式。它是二进制的,但它是一种相对理智的格式,允许存储具有任何类型数组数据的多个记录。要了解如何在Fortran上下文之外处理这些类型的文件,您可以查看following python script中的unpackNextRecord
函数。这应该相对容易翻译成任何语言(如果它还没有存在的话)。
现在,在Fortran端,您可以使用类似
的功能创建这些文件subroutine writeToFile[MyDataType](path, array)
implicit none
[MyDataType], intent(in), dimension(:) :: array
character(len=*), intent(in) :: path
character(len=:), allocatable :: dirname
integer(4) :: imt
dirname = getDirectory(path)
call makeDirectory(dirname)
call findNewFileHandle(imt)
open(imt, file = path, form = 'unformatted', status = 'replace')
write(imt) array
close(imt)
deallocate(dirname)
end subroutine
您也可以使用不同的数据类型多次写入文件句柄,例如,如果您有一些字符串和要保存的数字数组 - 只需添加更多write(imt)
个调用和输入你的助手子程序。要获取此处使用的辅助函数makeDirectory
和findNewFileHandle
,请参阅the following Fortran 90 module。
如果你习惯于处理文本文件,这个东西可能会有点奇怪,但是在Fortran中它更安全,更舒适 - 如果你想写纯文本,你会发现很多东西,直到你做对了,让我告诉你。
答案 2 :(得分:1)
我希望从C#调用长时间运行的Fortran例程,将Fortran例程编译为DLL,并将C#中的回调函数传递给Fortran例程。这样做的好处是您不会有多个进程争用同时访问同一个文件。
module MyLib
implicit none
interface
subroutine ProgressUpdateAction(percentProgress)
integer, intent(in) :: percentProgress
end subroutine
end interface
contains
subroutine DoWork(progressUpdate)
!DIR$ ATTRIBUTES DLLEXPORT :: DoWork
!DIR$ ATTRIBUTES ALIAS: 'DoWork' :: DoWork
!DIR$ ATTRIBUTES REFERENCE :: progressCallBack
procedure(ProgressUpdateAction), intent(in), pointer :: progressUpdate
integer, parameter :: STEP_COUNT = 9
integer :: i, percentProgress
do i = 1, STEP_COUNT
! Update the status.
percentProgress = (i - 1) * 100.0 / STEP_COUNT
call progressUpdate(percentProgress)
! Do something expensive...
end do
end subroutine
end module
在C#调用例程中创建一个匹配的委托。记得通过引用传递所有内容 - Fortran默认值。
public static class FortranLib
{
private const string _dllName = "FortranLib.dll";
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ProgressUpdateAction(ref int progress); // Important the int is passed by ref (else we could use built-in Action<T> instead of delegate).
[DllImport(_dllName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern void DoWork([MarshalAs(UnmanagedType.FunctionPtr)] ref ProgressUpdateAction progressUpdate);
}
class Program
{
static void Main(string[] args)
{
try
{
FortranLib.ProgressUpdateAction updateProgress = delegate(ref int p)
{
Console.WriteLine("Progress: " + p + "%");
};
FortranLib.DoWork(ref updateProgress);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
此处详细信息:http://www.luckingtechnotes.com/calling-fortran-from-c-monitoring-progress-using-callbacks/
答案 3 :(得分:0)
要制作一个不会影响代码性能的进度条,您可以执行以下操作。
在模块中创建全局变量
module progress
implicit none
real*8 :: progress_value = huge(1.d0)
integer :: progress_bar(2) = (/ 1, 1 /)
integer :: progress_refresh = 2
integer :: progress_unit = 66
logical :: progress_active = .False.
character*(64) :: progress_title = "UNDEFINED"
character*(128) :: progress_filename = "/tmp/progress"
end module
progress_value
:您要监控的值(例如运行平均值)progress_bar
:第一个索引将包含当前循环计数,第二个索引将包含总循环计数。比率dble(progress_bar(1))/dble(progress_bar(2))
将为您提供当前的进度百分比。progress refresh
:每次刷新之间的时间间隔(以秒为单位)progress_unit
:您将在其中写入信息的文件的单元号progress_active
:.True.
,否则为.False.
。progress_title
:让您确定您正在监控的内容。progress_filename
:您将在其中存储进度的文件的名称创建例程以启动/停止监控
初始化监控:
subroutine start_progress(max,title,progress_init)
use progress
implicit none
integer, intent(in) :: max
character*(*), intent(in) :: title
real*8, intent(in) :: progress_init
progress_bar(1) = 0
progress_bar(2) = max
progress_title = title
progress_active = .True.
progress_value = progress_init
call run_progress()
end
max
:循环次数的最大值title
:您监控的标题progress_init
:progress_value
终止监控:
subroutine stop_progress()
use progress
implicit none
progress_active = .False.
call write_progress()
end
在进度文件中打印数据的子程序
subroutine write_progress()
use progress
implicit none
open(unit=progress_unit,file=progress_filename)
write(progress_unit,'(A)') progress_title
write(progress_unit,'(F5.1,X,A)') dble(100*progress_bar(1))/dble(progress_bar(2)), '%'
write(progress_unit,*) progress_value
close(unit=progress_unit)
end
使用ALARM
信号的核心
recursive subroutine run_progress()
use progress
implicit none
call write_progress()
if (progress_active) then
call alarm(progress_refresh,run_progress)
endif
end
这是您使用它的方式:
program test
use progress
implicit none
integer :: i
integer, parameter :: nmax = 10
double precision :: s
! --> Before the loop, run start_progress
s = 0.d0
call start_progress(nmax, "Dummy loop", s)
do i=1,nmax
call sleep(1)
s = s+1.d0
! --> Update the global variables at the end of each loop cycle
! (there is no function call, so it is almost free)
progress_value = s
progress_bar(1) = i
enddo
! --> After the loop, call stop_progress
call stop_progress()
end
如果您不想使用文件而是使用命名管道(在编写例程中没有open / close语句), 由于其缓冲输出,它可能不适用于Fortran。你可以尝试
export GFORTRAN_UNBUFFERED_ALL=1
在你的shell中来改变它。
您可以在此处获取代码:https://gist.github.com/scemama/9977dc1290685b541f9c