特别声明:未经允许,请勿转载!
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 JuliaClassexport calculatefunction calculate(a::Float64, b::Float64)::Float64return a * pi + b^2endfunction calcMore(a, b)return ones(a, b)::Array{Float64,2};endfunction calc3par(a, b, c)return (a + b + c)::Float64;endfunction 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位的juliaSetDllDirectory(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#传递参数给juliaIntPtr 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++并不了解。