您现在的位置是:首页 >其他 >在C#WinForm中调用julia函数及在C#中传递参数到julia函数的使用示例网站首页其他

在C#WinForm中调用julia函数及在C#中传递参数到julia函数的使用示例

简介在C#WinForm中调用julia函数及在C#中传递参数到julia函数的使用示例

特别声明:未经允许,请勿转载! 

https://discourse.juliacn.com/t/topic/7189https://discourse.juliacn.com/t/topic/7189我在julia中国社区已提交了文章的最后部分未解决问题,大家后续可以在该链接中跟踪问题的回答进度。

好几年前就接触过julia,当时觉得并不好用,

如今julia版本已经来到了1.8.5版本,但是仍觉得它的生态还是不够好,很多问题都找不到答案。

我记录下当前的使用情况,在C#调用julia这块,结合前人的使用示例,我认为我这篇文章应该属于C#操作julia是最全的了。

在C#调用julia方面,目前已实现了如何使用以下函数(还有很多API接口函数可以在julia.h和jlapi.c中找到,但是要全部都会使用又是另一回事了):

jl_call1
jl_call2
jl_call3
jl_init__threading
jl_eval_string
jl_unbox_float64
jl_box_float64
jl_atexit_hook

此前搜索到前辈们留下的一个问题,

http://cn.voidcc.com/question/p-dhvlazdi-ux.htmlhttp://cn.voidcc.com/question/p-dhvlazdi-ux.html该链接是前人未结案的文章,至少我是这么认为。

我发现他的第1个和第2个结果是错误的,我把

public static extern IntPtr jl_box_float64(float value);

改为(float => double)

public static extern IntPtr jl_box_float64(double value);

得到的结果就正常了。

但是以下遇到的问题仍未解决.
julia脚本如下:

module JuliaClass
    export calculate

    function calculate(a::Float64, b::Float64)::Float64
        return a * pi + b^2
    end

    function calcMore(a, b)
        return ones(a, b)::Array{Float64,2};
    end

    function calc3par(a, b, c)
        return (a + b + c)::Float64;
    end

    function calcArray(a::Array{Float64,1})
        return (a[0] + a[1] + a[2])::Float64;
    end
end


C#脚本如下:


     //====================================================================
        [DllImport("kernel32.dll")]
        static extern bool SetDllDirectory(string lpPathName);

        [DllImport("libjulia.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern void jl_init__threading(string path);

        [DllImport("libjulia.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr jl_eval_string(string input);

        [DllImport("libjulia.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr jl_box_float64(double value);

        [DllImport("libjulia.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern double jl_unbox_float64(IntPtr value);

        [DllImport("libjulia.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr jl_get_global(IntPtr func, string name);

        [DllImport("libjulia.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr jl_call(IntPtr func, IntPtr[] v1, int v2);

        [DllImport("libjulia.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr jl_call1(IntPtr func, IntPtr v1);

        [DllImport("libjulia.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr jl_call2(IntPtr func, IntPtr v1, IntPtr v2);

        [DllImport("libjulia.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr jl_call3(IntPtr func, IntPtr v1, IntPtr v2, IntPtr v3);

        [DllImport("libjulia.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern void jl_atexit_hook(int a);
        //====================================================================
        
        private void button_CsCallJulia_Click(object sender, EventArgs e)
        {
            ///加载julia环境路径
            string julia_home_dir = Application.StartupPath + "\Julia-1.8.5\bin";//我的WinForm是32位的,所以安装的是32位的julia
            SetDllDirectory(julia_home_dir);
            jl_init__threading(julia_home_dir);
            ///加载julia脚本路径
            string jl_ScriptPath = "./JuliaScript/test_julia.jl";
            string jl_include = "include("" + jl_ScriptPath + "")";
            ///等效于julia>include("./JuliaScript/test_julia.jl")
            IntPtr jl_DoString = jl_eval_string(jl_include);
            ///执行julia脚本中JuliaClass模块的calculate函数
            IntPtr jl_ret = jl_eval_string("JuliaClass.calculate(2.0,4.0)");///julia函数返回值给C#中的IntPtr类型
            double cs_val = jl_unbox_float64(jl_ret);///julia拆箱转换为C#的double数据类型
            Console.WriteLine("result1={0}", cs_val);
            ///C#传递参数给julia
            IntPtr jl_function = jl_eval_string("JuliaClass.calculate");
            IntPtr jl_par1 = jl_box_float64(3.0);///C#参数1装箱
            IntPtr jl_par2 = jl_box_float64(4.0);///C#参数2装箱
            jl_ret = jl_call2(jl_function, jl_par1, jl_par2);///传入到julia指定模块中的函数,以及参数,注:jl_call2只能传递1个函数和2个参数
            cs_val = jl_unbox_float64(jl_ret);///julia拆箱转换为C#的double数据类型
            Console.WriteLine("result2={0}", cs_val);

            jl_function = jl_eval_string("JuliaClass.calc3par");
            jl_par1 = jl_box_float64(12.0);
            jl_par2 = jl_box_float64(13.0);
            IntPtr jl_par3 = jl_box_float64(14.0);
            jl_ret = jl_call3(jl_function, jl_par1, jl_par2, jl_par3);
            cs_val = jl_unbox_float64(jl_ret);
            Console.WriteLine("result3={0}", cs_val);

        }


问题就是:
1.我不知道如何在C#里通过jl_call传递一个数组到julia中的calcArray函数,
我尝试->

            jl_function = jl_eval_string("JuliaClass.calcMore");
            IntPtr[] jl_par = new IntPtr[3] { (IntPtr)11, (IntPtr)12, (IntPtr)13 };
            jl_ret = jl_call(jl_function, jl_par, 3);
            Console.WriteLine("result4={0}", jl_ret);


运行这段代码它报错如下:

result1=22.2831853071796
result2=25.4247779607694
result3=39

引发的异常:“System.AccessViolationException”(位于 RobotTestingAPP.exe 中)
“System.AccessViolationException”类型的未经处理的异常在 RobotTestingAPP.exe 中发生 
尝试读取或写入受保护的内存。这通常指示其他内存已损坏。

因此我不知道在C#中如何正确使用jl_call,搜索全网找不到答案!
2.如何在C#中使用jl_base_module等函数,如果是用C++调用,则是很方便,但我对C++并不了解。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。