zoukankan      html  css  js  c++  java
  • Rust初步(六):在C#中使用Rust组件

    上一篇文章,我们通过实例比较了一下C#和Rust的性能表现,应该说在Release模式下面,Rust进行计算密集型的运算还是有些比较明显的优势的。那么,我们有没有可能,在C#中做一些快速应用开发,而一些核心的算法用Rust来实现呢?答案是可以的。

    编写Rust代码

    下面这段代码,保存在lib.rs文件中

    use std::thread;
    
    #[no_mangle]
    pub extern fn process(){
        let handles :Vec<_> =(0..10).map(|_|{
            thread::spawn(||{
                let mut x= 0;
                for _ in (0..5_000_000){
                    x+=1
                }
                x
            })
        }).collect();
    
    
        for h in handles{
            println!("Thread finished with count={}",h.join().map_err(|_| "Could not join a thread!").unwrap());
        }
    
        println!("done!");
    }
    

    这段代码的几个关键点在于

    1.声明为pub,也就是说要让外部可以访问到

    2.声明为extern,意思应该也是说希望外部可以访问

    3.添加一个标记 #[no_mangle],这个开关据说是阻止编译器在编译的时候,重命名函数。我也还不是很理解,先照这么做吧

    其他部分就是标准的Rust代码了

    生成Rust的动态链接库

    默认情况下,Rust编译的库叫做静态链接库,如果我们需要编译动态链接库的话,需要在Cargo.toml文件中定义

    image

    然后,运行cargo build -- release命令生成动态链接库(dll)

    image

    我们在输出目录中,可以看到一个countlib.dll 的动态链接库文件

    image

    在C#中使用这个动态链接库

    你可以将countlib.dll放在C#编译输出目录的根目录下面

    using System;
    using System.Threading.Tasks;
    using System.Diagnostics;
    using System.Threading;
    using System.Runtime.InteropServices;
    
    
    namespace ConsoleApplication1
    {
        class Program
        {
    
            [DllImport("countlib.dll",CallingConvention= CallingConvention.Cdecl)]
            public static extern void process();
    
            static void Main(string[] args)
            {
                Stopwatch watch = new Stopwatch();
                watch.Start();
    
                //Parallel.For(0, 10, i =>
                //{
                //    var x = 0;
                //    for (int j = 0;  j< 5000000; j++)
                //    {
                //        x += 1;
                //    }
                //    Console.WriteLine("线程:{0} 完成计数",Thread.CurrentThread.ManagedThreadId);
                //});
    
                process();//调用Rust里面的程序process进行计算
    
                watch.Stop();
                Console.WriteLine("耗时:{0}秒", watch.Elapsed.TotalSeconds);
                Console.Read();
            }
        }
    
    }
    
     
    在Debug模式下面的耗时为 0.002秒(提升太明显了吧)
    image
     
    在Release模式下面的耗时为0.002秒(基本上跟Debug模式不相上下,很神奇吗)
    image
     
    那么,这个性能表现,几乎接近了直接使用Rust的性能,比原先用C#的方式提高了5倍。
     
    如此说来,计算密集型(尤其是需要用到多线程,多核)的任务,可以用Rust来编写,然后在C#中调用。
     
    【特别注意】
    cargo build默认情况下会根据当前计算机的配置进行编译,例如我是64位的计算机,那么编译出来的dll也是64位的,在C#中用的时候,就需要同样设置为64位,否则就会出现错误
    image
     

    那么,cargo build是否可以指定对应的平台进行编译呢?可以通过指定 --target参数来实现,可用的值主要有

    x86_64-pc-windows-gnu
    i686-unknown-linux-gnu
    x86_64-unknown-linux-gnu
    详细可以参考 http://doc.crates.io/manifest.html
    我用下面这样用就可以编译一个通用的dll(既能用于32位,也能用于64位——采用WOW模式)
    image
     
    其实这个编译选项,类似于我们在Visual Studio中使用Any CPU进行编译
    image
  • 相关阅读:
    几个常用排序的代码实现堆排序|快排|归并排序 Marathon
    0647回文子串 Marathon
    任意输入一个日期输出是当年的第几天星期几
    从输入URL到浏览器显示页面发生了什么
    常用链接整理
    computed 与 method
    将博客搬至CSDN
    leetcode_Two Sum
    VC++6.0与Office2010冲突解决方案
    C&C++_malloc函数
  • 原文地址:https://www.cnblogs.com/chenxizhang/p/4760674.html
Copyright © 2011-2022 走看看