65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 .NET Framework 进行高级数值分析的高性能应用程序

2007 年 12 月 19 日

CPOL

15分钟阅读

viewsIcon

37970

本文探讨了 .NET 平台在数值分析方面的优势,.NET 应用程序性能提升的技巧,IMSL C# 数值库在 Microsoft .NET 应用程序中的功能,以及 .NET Framework 用于高级分析的功能。

引言

近年来,.NET Framework 的编程范例已迅速被金融服务界采纳用于高级数值分析,金融服务界素来以早期采用者引领潮流而闻名。.NET Framework 因多种原因成为一个强大的平台,包括高级的程序员生产力、类型安全、安全策略以及开箱即用的便利性。然而,许多程序员可能会质疑该平台是否适合高级数值应用程序。

要了解更多关于使用 IMSL C# 数值库进行高级分析的高性能应用程序的信息,或申请免费评估,请单击此处!您还可以预订您的 20% 折扣,稍后购买!

本文将探讨 .NET 平台在数值分析方面的一些优势。还将介绍提高 .NET 应用程序性能的许多技巧。此外,随着需要高级数学和统计算法的程序被开发或移植到 .NET Framework,自然需要第三方数值库。IMSL® C# 数值库将成为许多用户此类实现的关键部分。本文还将演示该库中允许 .NET Framework 用于高级分析的几项功能。

随着组织从使用仅总结历史数据的基本分析转向预测分析(使组织能够通过数学和统计技术预测结果),高级分析正在跨多个行业使用。高级分析使组织能够更好地规划,模拟新机会,并提高预算和预测的准确性。零售商可以更准确地管理库存,医疗保健公司可以提高员工生产力,金融服务公司可以提高客户保留率。

.NET Framework 的优势

.NET Framework 的主要优势在于“程序员生产力”。这个术语包含许多特性,但我们将只关注两个。首先是语言灵活性。其理念是您可以以任何支持的语言编写代码,使用以任何其他支持的语言编写的库,并且仍然能够利用整个平台的各个方面。无论您是编写桌面应用程序、ASP.NET Web 应用程序的后台代码,还是 Web 服务的客户端或服务器端,您都可以使用 C#、Visual Basic.NET、J#、Managed C++ 或任何二十多个第三方语言。因此,GUI 专家可以使用 Visual Basic.NET 编写,而业务逻辑层使用 C++ 编写,数据库交互使用 C# 编写。这些代码片段都将编译为 Microsoft 中间语言 (MSIL 或简称 IL),并且可以无缝地相互操作。

程序员生产力的另一个主要方面是可用工具集的成熟度和完整性。具体来说,Visual Studio IDE 已发展到 .NET 世界,成为提高程序员生产力的重要因素。虽然仍然有使用 Visual Studio IDE 生成原生 Windows 代码的能力,但它已完全与 .NET Framework 集成。Visual Studio 由语法高亮代码编辑器、调试器和 GUI 设计器组成,所有这些都与各种编译器集成,是一个强大的工具。与许多其他编程环境不同,Visual Studio 工具集中在一个地方。平均而言,程序员只需几分钟就可以创建从桌面应用程序到 Web 服务的任何内容。结合平台的语言灵活性和第三方库(如果完全符合 .NET 标准),它们将具有语言无关的元数据。这意味着程序员可以在他们的 Visual Studio 项目中添加对库的引用,而 IDE 会解析这些信息,并在程序员编写代码时为他们提供代码完成和 IntelliSense 信息。有了触手可及的 API,开发人员将不再需要反复查阅文档。

该平台的其他优势包括部署策略和元数据、安全性、鲁棒性和可靠性。.NET Framework 上构建的每个 EXE 或 DLL 程序集都包含元数据,提供关于自身以及它依赖的其他程序集和类型的版本信息。结合版本策略或发布者策略,开发人员可以更容易地避免臭名昭著的“DLL Hell”综合征。在安全性方面,可验证组件(使用 C# 或 VB.NET 自然生成,并在 C++ 中使用“/clr:safe”标志)保证代码不会违反安全设置,并且如果代码失败,它会以非灾难性的方式失败。允许公共语言运行时 (CLR) 在运行时验证安全设置,为您的应用程序提供前所未有的安全性。此外,CLR 将代码与操作系统隔离,确保即使发生灾难性崩溃,其影响也容易隔离。凭借所有上述功能和其他功能(如类型安全(代码只能访问其授权使用的内存位置)),为 .NET 平台编写的应用程序可能仍然不能完全没有 bug,但比许多替代方案更具鲁棒性和安全性。

最大化 .NET Framework 的性能

当人们考虑在新平台上编写计算密集型代码时,性能问题自然会出现。虽然 .NET Framework 和 CLR 具有一些会导致人们认为它是解释语言环境的特性,但即时 (JIT) 编译的出现使其性能接近原生语言实现。代码(用任何支持的语言编写)最初被编译为 IL。这种语言虽然读起来像汇编语言,但并不是您的桌面处理器能够理解和执行的代码。在运行时,IL 由即时编译器 (JITter) 编译为特定于机器的原生可执行代码。这些代码将被编译以匹配要执行代码的架构(例如,Pentium IV x86 与 Xeon EM64T 与 Itanium IA64)。正是通过这个高度优化的 JITter 步骤,其性能才比任何解释性语言都要接近原生代码。当然,JITter 编译代码时会有轻微的延迟。可以通过使用名为 ngen 的原生映像生成器实用程序来克服这种延迟。通过“ngen”您的代码,.NET 程序集将被预编译,并准备好在本地环境中执行。

“接近原生”的性能当然取决于编写 .NET 应用程序时遵循一些最佳实践。以下是一些在此环境中获得最佳性能的技巧。

  1. 小心使用值类型和对象: 值类型和对象在内存中的处理方式截然不同。值类型创建成本非常低,并且在堆栈上创建。相反,实例化一个对象至少成本稍高,即使是简单的对象,它们也在堆上创建。基本上,当您有机会使用 int 或 Integer 时,请尽可能选择 int。有时您可能需要将值类型转换为引用;此操作称为装箱。装箱和拆箱是相对昂贵的操作,应尽可能避免。关键在于 C# 和 Visual Basic.NET 等高级 .NET 语言会自动执行一些装箱操作。如果您不小心,许多性能优化会因为您可能不知道的自动装箱而丢失。编写 Managed C++ 时,所有装箱操作都必须手动完成,因此提高了额外的意识。
  2. 使用数组: 根据程序员在其他语言中编写高性能代码的个人经验,可能自然会使用不变的局部变量编写循环,而不是使用数组的属性。例如,考虑以下 C# 代码来遍历数组

    int len = myArray.length;
    for (int i=0; i<len; i++) {
    myArray[i] *= 2;
    
    }

    在这里,我们知道 `myArray` 的长度在循环内部不会改变,因此我们将其计算一次,将值存储在名为 `len` 的变量中,然后将其用于循环的上限。令人惊讶的是,以下代码实际上会生成少四行 IL 代码

    for (int i=0; i<myArray.length; i++) {
    myArray[i] *= 2;
    }

    因为编译器知道 `myArray` 的某些信息,所以此循环只需要一次边界检查。在第一种情况下,`len` 变量可能在循环内部更改,因此需要额外的工作来确保 `myArray` 不会越界访问。这些内部检查有利于 .NET 平台的健壮性,但不能提高性能。

    如果您在开发时知道 `myArray` 的长度信息,您可以使用常量作为循环的终点。在这里将实现最佳性能,因为生成的 IL 代码行数最少(比上面第二个示例少两行)。当然,`myArray` 的大小必须在编译时知道,并且不能在运行时更改。

  3. 最小化异常抛出: 同样,根据程序员对面向对象编程 (OOP) 概念的了解,可能会倾向于将异常作为控制程序流程的一种方式。在 C 和 Fortran 的过程式编程时代,程序员有许多方法可用于控制代码流程。来自这种背景的一些开发人员可能会倾向于“利用”OOP 的某些特性。但是,抛出异常是一项非常昂贵的操作,需要进行堆栈回溯。因此,应根据程序设计或 API 指定来抛出异常,而不是用于控制应用程序的流程。
  4. 避免手动垃圾回收: 对于过程式程序员或总体上激进的程序员来说,对 OO 世界不熟悉,可能会倾向于手动调用垃圾收集器。 .NET 中的垃圾收集器是一个独立的线程,它监视对象的用法,并自动释放不再引用的对象占用的内存。该方案是一个成熟且设计精良的概念。如果您刚刚释放了大量对象,可能会有调用垃圾收集器以更早地释放其内存的冲动。但是,应避免这样做,因为它只会中断垃圾收集器设计的操作。

适用于 Microsoft .NET 应用程序的 IMSL C# 库

随着将遗留应用程序移植到 .NET Framework,用户将需要原始应用程序中使用的任何第三方库的新版本。同样,随着以 .NET 语言编写新应用程序,将需要库来填补专业知识不足或内部开发成本过高的领域。为了满足这些需求,Visual Numerics 开发了 IMSL C# 数值库。IMSL C# 库涵盖了广泛的数学和统计功能,并用 100% C# 编写。它是一个完全托管的程序集,可以无缝集成到任何 .NET 应用程序中:无需处理包装的代码或调用原生的 C/C++ DLL。作为具有语言无关元数据的完全托管代码,该库可以像任何其他 .NET 语言(如 Visual Basic.NET)一样轻松地从 C# 使用。

IMSL C# 库包含六个命名空间:`Imsl`、`Imsl.Math`、`Imsl.Stat`、`Imsl.Finance`、`Imsl.DataMining.Neural` 和 `Imsl.Chart2D`。该库的大部分功能位于 `Math` 和 `Stat` 命名空间中,而 `Finance` 中包含一些实用的金融例程,`Imsl` 命名空间中包含异常处理类。`DataMining` 命名空间包含神经网络实现,`Chart2D` 包含灵活的桌面和基于 Web 的图表类。IMSL C# 库建立在标准的 .NET Base Class Library 之上,其功能既扩展了 .NET Framework 以使用户能够编写自己的自定义数值算法,又利用了超过 35 年的成熟算法。

IMSL C# 库在几个关键领域得到了扩展,以允许程序员编写高级分析例程

  1. 复数: 在数值计算中,出于多种原因需要复数,但 .NET Framework 中没有内置支持。IMSL C# 库包含 `Imsl.Math.Complex` 实现,它是一个不可变的结构。选择此结构是为了让 Complex 对象尽可能像基本数据类型一样运行。包含许多方法,如 Conjugate、Real、Abs、Cos 等,用于执行复数的一系列基本计算。此外,还通过利用 .NET 的运算符重载功能提供了标准运算符,如加法、除法、乘法、减法、相等性、不等式和一元否定。最后,构造函数被重载,允许用户从另一个复数、一个实数双精度数创建复数,或通过提供实部和虚部作为双精度值来创建复数。
  2. 分布函数: 要构建许多类型的统计分析例程,必须计算各种分布函数。此功能由 `Imsl.Stat.Cdf` 类提供,该类有 50 多个不同的方法,可返回不同的累积分布函数、概率密度函数及其反函数。同样,要创建统计模型,还需要各种随机数分布。`Imsl.Stat.Random` 类包装 `System.Random` 以返回“NextDouble”,但它还能够返回 20 多种其他分布的“Next”。请注意,还有一个 Mersenne Twister 实现可以替换标准的 System.Random 生成器。
  3. 矩阵操作: 以有意义的方式操作矩阵的能力对于许多不同类型的数值应用程序也至关重要。为此,IMSL C# 库包含 `Imsl.Math.Matrix` 类,该类完全由公共静态方法组成,用于将标准的 double[,] 数组视为矩阵。方法是典型的:`Add`、`Multiply`、`Subtract`、`Transpose`、`CheckSquareMatrix`、`ForbeniusNorm`、`InfinityNorm` 和 `OneNorm`。您通常需要的唯一其他操作是矩阵求逆,这里有几个选项嵌入在其他类中(`LU`、`ComplexLU`、`Cholesky` 和 `SVD`),因为逆矩阵是这些分解的副产品。还提供复数矩阵操作例程。

使用 Visual Studio 和 IMSL C# 库

Screenshot - image001.jpg

大多数为 .NET Framework 编写代码的开发人员将使用 Visual Studio 作为他们首选的工具。Visual Studio 是一个强大而成熟的集成开发环境 (IDE),对 .NET 语言提供了出色的支持和了解。通过这个单一应用程序,用户可以编写代码、设计界面、编译应用程序并调试最终产品。使用 IMSL C# 库非常简单,并且因为它纯粹是 C# 和托管代码,所以 Visual Studio 能够比以往任何时候都更容易地进行程序集编程。

首先,加载现有 .NET 项目或创建一个新项目;使用的语言无关紧要。下一步是将对 IMSL C# 库程序集 `ImslCS.dll` 的引用添加到项目中。这可以通过在解决方案资源管理器中右键单击项目并选择“添加引用…”或在菜单栏中选择“项目”并选择“添加引用…”来完成。无论哪种方式,都会出现“添加引用”对话框。浏览到 `ImslCS.dll` 程序集,然后单击“确定”将其添加到项目中。请注意,如果您已将程序集添加到全局程序集缓存 (GAC),则“复制本地”属性将设置为 false,项目的 bin 目录将不包含 DLL 的副本。否则,“复制本地”将为 true,并且 `ImslCS.dll` 将被复制到项目下的相应 bin 目录。

此时,IMSL C# 库的所有功能都触手可及。通过在项目代码中添加命名空间来尝试一下。在程序的顶部,添加一行,例如 C# 的“using Imsl.Math;”,VB.NET 的“Imports Imsl.Math”,或 C++ 的“using namespace Imsl::Math;”。这行显然取决于项目的语言,但您应该注意到,在键入“Imsl.”后,会弹出代码完成对话框,其中列出了程序集中所有可访问的命名空间。这表明引用已正确添加,并且 IMSL 算法可以轻松添加到您的应用程序中。

关于易用性和跨语言功能的一点说明:考虑您需要进行一些预测并希望使用 ARMA 模型的情况。IMSL C# 库包含一个名为 ARMA 的类,并且文档以硬拷贝或电子形式提供,包括编译帮助 (chm) 和 PDF 版本。但是,您正在编写代码,并且宁愿不中断以查找文档以回忆此类构造函数所需的参数。在这里,Visual Studio 的一项称为 IntelliSense 的功能将提供帮助。对于上面提到的三种语言,这里有一些您尝试创建 ARMA 对象时 IntelliSense 会显示的屏幕截图。


在 C# 中: Screenshot - image002.jpg

在 VB.NET 中: Screenshot - image003.jpg

在 C++ 的托管扩展中: Screenshot - image004.jpg

请注意,构造函数的参数列表如何以项目语言显示。因此,虽然算法是用 C# 编写的,但语言无关的元数据允许 Visual Studio 在当前环境中按预期显示代码。

结论

.NET 平台是编写高性能数值分析应用程序和移植遗留数值应用程序的可行选择。编写现代框架代码的较高程序员生产力在代码编写时和将来维护代码时都非常有价值。对面向对象编程的理解以及 .NET 的一些实现有助于从应用程序中榨取额外的性能。第三方库(如适用于 Microsoft .NET 应用程序的 IMSL C# 数值库)使开发人员能够专注于编写更好的应用程序,而无需编写复杂的算法。以这种方式重用商业质量的代码可以节省初始时间和长期时间,因为减少了文档记录、测试和维护代码所需的时间。将此类组件集成到 Visual Studio 等 IDE 中非常容易,进一步提高了程序员的生产力。

要了解更多关于使用 IMSL C# 数值库进行高级分析的高性能应用程序的信息,或申请免费评估,请单击此处!您还可以预订您的 20% 折扣,稍后购买!

版权所有 © 2005-2007 Visual Numerics, Inc. 保留所有权利。
在美国印刷。

出版历史
2007 年 9 月 - 更新
2005 年 9 月 - 首次发布

© . All rights reserved.