追求性能第一部分:内联 C、OpenMP 和 Perl 数据语言 (PDL)

追求性能第一部分:内联 c、openmp 和 perl 数据语言 (pdl)

有时,一个人的代码必须简单地执行,而诸如美观、“聪明”或对单一语言解决方案的承诺之类的原则则完全不适用。
在 tprc 我做了一个演讲(这里是幻灯片)关于如何做到这一点
可以针对生物信息学应用程序完成,但我认为有必要使用一个更简单的示例来说明最大化 perl 性能的潜在场所
程序员在数据密集型应用程序中工作时可以随意使用。

所以这是一个玩具问题来说明这些选项。给定一个非常大的双精度浮点数组使用以下函数将它们变换cos(sin(sqrt(x)))
该函数有 3 个嵌套的浮点运算。这是一个评估成本高昂的函数,尤其是在必须计算大量值的情况下。我们可以合理生成
使用以下代码快速获取 perl 中的数组值(以及我们将要检查的解决方案的一些副本):

my $num_of_elements = 50_000_000;my @array0 = map { rand } 1 .. $num_of_elements;    ## generate random numbersmy @array1 = @array0;                               ## copy the arraymy @array2 = @array0;                               ## another copymy @array3 = @array0;                               ## yet another copymy @rray4  = @array0;                               ## the last? copymy $array_in_pdl      = pdl(@array0);    ## convert the array to a pdl ndarraymy $array_in_pdl_copy = $array_in_pdl->copy;    ## copy the pdl ndarray

可能的解决方案包括以下:

在 perl 中使用 for 循环进行就地修改。

for my $elem (@array0) {    $elem = cos( sin( sqrt($elem) ) );}

使用内联 c 代码遍历数组并在 c 中就地转换。 。有效地使用 c 进行就地映射。在 c 中访问 perl 数组(c 中的 av*)的元素尤其如此
如果使用 perl 5.36 及更高版本,则性能更高,因为该版本的 perl 中引入了优化的获取函数。

void map_in_c(av *array) {  int len = av_len(array) + 1;  for (int i = 0; i < len; i++) {    sv **elem = av_fetch_simple(array, i, 0); // perl 5.36 and above    if (elem != null) {      double value = svnv(*elem);      value = cos(sin(sqrt(value))); // modify the value      sv_setnv(*elem, value);    }  }}

使用内联 c 代码来转换数组,但将转换分解为 3 个连续的 c for 循环。 这是一个真正关于权衡的实验:现代 x86 处理器有一个专门的,
向量化平方根指令,因此编译器也许可以弄清楚如何使用它来加速至少一部分计算。另一方面,我们将降低算术强度
每个循环并访问相同的数据值两次,因此可能会为这些重复的数据访问付出代价。

void map_in_c_sequential(av *array) {  int len = av_len(array) + 1;  for (int i = 0; i < len; i++) {    sv **elem = av_fetch_simple(array, i, 0); // perl 5.36 and above    if (elem != null) {      double value = svnv(*elem);      value = sqrt(value); // modify the value      sv_setnv(*elem, value);    }  }  for (int i = 0; i < len; i++) {    sv **elem = av_fetch_simple(array, i, 0); // perl 5.36 and above    double value = svnv(*elem);    value = sin(value); // modify the value    sv_setnv(*elem, value);  }  for (int i = 0; i < len; i++) {    sv **elem = av_fetch_simple(array, i, 0); // perl 5.36 and above    double value = svnv(*elem);    value = cos(value); // modify the value    sv_setnv(*elem, value);  }}

使用 openmp 并行化 c 函数循环。 在上一篇文章中,我们讨论了如何从 perl 中控制 openmp 环境并编译 openmp 感知的 inline::c 代码
由 perl 使用,所以让我们将这些知识付诸实践!在程序的 perl 方面,我们将这样做:

use v5.38;use alien::openmp;use openmp::environment;use inline (    c    => 'data',    with => qw/alien::openmp/,);my $env = openmp::environment->new();my $threads_or_workers = 8; ## or any other value## modify number of threads and make c aware of the change$env->omp_num_threads($threads_or_workers);_set_num_threads_from_env();## modify runtime schedule and make c aware of the change$env->omp_schedule("guided,1");    ## modify runtime schedule_set_openmp_schedule_from_env();

在程序的 c 部分,我们将执行此操作(已经讨论了 openmp 环境的辅助函数
之前,因此这里不再重复)。

#include void map_in_c_using_omp(av *array) {  int len = av_len(array) + 1;#pragma omp parallel  {#pragma omp for schedule(runtime) nowait    for (int i = 0; i < len; i++) {      sv **elem = av_fetch_simple(array, i, 0); // perl 5.36 and above      if (elem != null) {        double value = svnv(*elem);        value = cos(sin(sqrt(value))); // modify the value        sv_setnv(*elem, value);      }    }  }}

perl 数据语言 (pdl) 可以拯救你。 pdl 模块集是另一种加速操作的方法,可以将程序员从 c 语言中解救出来。它还能在给定正确指令的情况下自动并行化,所以为什么不使用它呢?

use pdl;## set the minimum size problem for autothreading in pdlset_autopthread_size(0);my $threads_or_workers = 8; ## or any other value## pdl## use pdl to modify the array - multi threadedset_autopthread_targ($threads_or_workers);$array_in_pdl->inplace->sqrt;$array_in_pdl->inplace->sin;$array_in_pdl->inplace->cos;## use pdl to modify the array - single threadset_autopthread_targ(0);$array_in_pdl_copy->inplace->sqrt;$array_in_pdl_copy->inplace->sin;$array_in_pdl_copy->inplace->cos;

使用8个线程我们得到这样的东西

inplace benchmarksinplace  in         perl took 2.85 secondsinplace  in perl/mapcseq took 1.62 secondsinplace  in    perl/mapc took 1.54 secondsinplace  in   perl/c/omp took 0.24 secondspdl benchmarksinplace  in     pdl - st took 0.94 secondsinplace  in     pdl - mt took 0.17 seconds

使用16个线程我们得到了这个!

Starting the benchmark for 50000000 elements using 16 threads/workersInplace benchmarksInplace  in         Perl took 3.00 secondsInplace  in Perl/mapCseq took 1.72 secondsInplace  in    Perl/mapC took 1.62 secondsInplace  in   Perl/C/OMP took 0.13 secondsPDL benchmarksInplace  in     PDL - ST took 0.99 secondsInplace  in     PDL - MT took 0.10 seconds

一些观察:

openmp 和 pdl 的多线程 (mt) 会响应工作线程的数量,而解决方案则不会。因此,这些基准测试中纯 perl 和内联非 openmp 解决方案的时序给出了性能自然变化的想法用 c 语言编写地图版本的代码,性能提高了约 180%(对比 perl 和 perl/mapc)。在单线程中使用 pdl 性能提高了 285-300%(对比 pdl – st 和 perl 计时)。重复内存访问是要付出代价的(对比 perl/mapc 与 perl/mapcseq)openmp 和多线程 pdl 操作提供了类似的性能(尽管 pdl 在这些示例中显得更快)。代码运行速度快了 23-30 倍。总之,在 perl 中,有原生(pdl 模块)和外来(c/openmp)解决方案来加速数据密集型操作,那么为什么不广泛而明智地使用它们来提高 perl 程序的性能呢?

以上就是追求性能第一部分:内联 C、OpenMP 和 Perl 数据语言 (PDL)的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1456273.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月18日 08:38:56
下一篇 2025年12月18日 08:39:08

相关推荐

  • 针对不同业务场景,C++ 框架如何选择適切的架构模式来提高可扩展性和维护性?

    选择 c++++ 架构模式以增强可扩展性和维护性:单体架构:简单,适用于小型独立应用程序。分层架构:提高可扩展性和可维护性,适合大型应用程序。mvc 架构:分离视图、逻辑和控制,增强可扩展性。微服务架构:松散耦合服务,提高可扩展性和灵活性。事件驱动的架构:使用发布-订阅模式,增强可扩展性和松散耦合。…

    2025年12月18日
    000
  • 不同类型 C++ 框架的最佳实践有什么差异?

    不同 c++++ 框架类型的最佳实践各不相同,具体取决于其设计理念和目标受众。web 框架遵循 mvc 架构、restful 设计和使用模板引擎,而测试框架使用单元测试、模拟和 bdd。orm 框架实现对象-关系映射,惰性加载和审计跟踪。di 框架采用依赖反转、配置文件和对象作用域管理依赖关系。 不…

    2025年12月18日
    000
  • C++ 框架与其他编程语言框架的最佳实践比较如何?

    最佳实践比较:c++++ 框架:使用容器类和智能指针进行资源管理。避免全局变量并实践模块化开发。利用代码生成工具确保跨平台兼容性。python 框架:遵循 mtv 架构,使用 orm,采用敏捷开发方法。自动化测试并利用依赖注入。java 框架:遵循分层架构,采用注释驱动开发和领域驱动设计。使用依赖注…

    2025年12月18日
    000
  • C++ 框架性能优化最佳实践有哪些?

    通过应用九项最佳实践,可显著提高 c++++ 框架性能:避免内存分配;优化数据结构选择;并行化任务;缓存数据;减少不必要的复制;优化算法;使用性能分析工具;避免死锁和竞争条件;在性能和功能间取得平衡。 C++ 框架性能优化最佳实践 在 C++ 框架开发中,性能优化至关重要。以下是一些最佳实践,可以帮…

    2025年12月18日
    000
  • 如何在C++框架中识别和修复性能瓶颈?

    在 c++++ 框架中识别和修复性能瓶颈的方法如下:识别瓶颈:性能分析代码审查调试和剖析修复瓶颈:优化算法和数据结构减少资源泄漏并行化和异步操作 如何在 C++ 框架中识别和修复性能瓶颈 简介 性能瓶颈会在大型 C++ 应用程序中引起严重的性能问题,识别和解决这些瓶颈对于优化应用程序的性能至关重要。…

    2025年12月18日
    000
  • 敏捷开发中的C++框架与C++库

    敏捷开发中,使用 c++++ 框架和库可以显着提升开发效率和代码质量。框架提供稳定的基础架构和工具集,简化常见开发任务,如 qt 和 wxwidgets。库提供模块化功能和数据,如 boost、eigen 和 opencv,节省开发时间并提高代码质量。这些组件带来的优势包括开发效率提升、代码质量提高…

    2025年12月18日
    000
  • 哪种C++框架支持跨平台移动开发?

    qt 框架是一个跨平台移动开发工具,可简化不同平台上的应用程序开发。它提供跨平台支持、原生外观、易用性,并包含各种组件。使用 qt 构建跨平台移动应用程序的步骤包括创建项目、设计用户界面、添加功能,然后编译和部署。 使用 Qt 框架进行跨平台移动开发 简介 Qt 是一个广泛且强大的跨平台框架,用于构…

    2025年12月18日
    000
  • C++框架与C++库的区别对比

    c++++框架提供应用程序结构,库提供预定义功能;框架具有高度可扩展性,控制流和紧密耦合;库具有有限的可扩展性,松散耦合和较低的学习曲线。实战案例:spring framework(框架)、boost c++ 库(库)。 C++ 框架与 C++ 库的区别对比 在软件开发中,C++ 框架和 C++ 库…

    2025年12月18日
    000
  • 基于组件的软件开发(CBSE)中的C++框架与C++库

    在基于组件的软件开发中,c++++ 框架和 c++ 库共同提供预构建组件和功能,简化应用程序构建。c++ 框架提供应用程序骨架,包含通用功能,如用户界面管理和数据访问,例如 qt、boost 和 wxwidgets。c++ 库提供特定领域的组件和功能,例如 stl(数据结构和算法)、opencv(计…

    2025年12月18日
    000
  • C++框架在不同应用场景下的最佳实践和性能调优如何?

    在不同应用场景下使用c++++框架的最佳实践:游戏开发:使用轻量级框架,如glfw或sdl。优化内存管理,使用智能指针和对象池。利用多线程。高性能计算:选择合适的数据结构。并行化算法。优化内存访问。金融交易系统:强调低延迟,使用非阻塞算法和数据结构。确保数据完整性,使用加密、安全协议和冗余机制。追求…

    2025年12月18日
    000
  • C++框架终极指南:开源与商业的优劣解说

    开源 c++++ 框架免费、可定制且社区支持丰富,但缺乏正式支持和质量可能参差不齐;商业 c++ 框架提供高质量、企业级功能和支持,但许可费用昂贵且定制有限。选择时考虑项目规模、定制需求、成本和支持要求。 C++ 框架终极指南:开源与商业的优劣解说 引言 在大型软件开发项目中,C++ 框架是构建健壮…

    2025年12月18日
    000
  • 深入解析C++框架的架构与设计模式

    c++++框架提供了预构建组件和设计模式,用于构建可靠的应用程序。架构分层,包括服务、数据访问、表示和网络层。设计模式包括单例、工厂方法、观察者和策略模式,以增强框架的灵活性和可维护性。例如,使用boost::asio框架的网络服务器演示了服务层(server类)、网络层(boost::asio)和…

    2025年12月18日
    000
  • 在大型项目中有效使用C++框架的策略

    在大型 c++++ 项目中有效使用框架的策略包括:选择合适的框架,考虑项目需求。制定明确定义框架用途、职责的策略。采用模块化设计,使用框架的模块化功能创建可复用组件。利用代码生成器和模板自动化重复性任务。集成框架代码库与持续集成系统,自动化构建、测试和部署。清晰记录框架代码、功能和交互方式。 在大型…

    2025年12月18日
    000
  • C++框架的最佳实践与反模式

    c++++ 框架最佳实践:使用依赖注入提高可测试性和可维护性。遵循分离关注点原则,将代码分解为模块化单元。使用枚举代替魔数,提供有意义的名称。反模式:过度继承会导致代码脆弱和难以维护,优先考虑组合。使用全局变量污染命名空间,导致代码不易维护。忽略异常处理会导致应用程序意外终止,失去错误信息。 C++…

    2025年12月18日
    000
  • C++ 框架与其他软件架构的比较

    c++++ 框架为 c++ 应用程序开发提供了可重用性、快速开发和代码一致性,而其他软件架构,如分层架构、微服务架构和事件驱动架构,则提供了灵活性、可扩展性和其他优势。实战案例比较显示,分层架构在灵活性方面优于 c++ 框架,而 c++ 框架在开发速度和维护方便性方面更好,因此根据应用程序的特定需求…

    2025年12月18日
    000
  • C++ 框架如何简化大型软件项目中的沟通与协作

    c++++ 框架通过以下方式简化大型软件项目中的沟通和协作:架构风格:提供清晰的项目结构,允许模块化代码。代码生成器:自动生成代码,减少手动编码工作量,确保代码一致性。版本控制:集成版本控制系统,简化代码合并和冲突解决,确保代码完整性。 C++ 框架:提升大型软件项目中的沟通与协作 在大型软件项目中…

    2025年12月18日
    000
  • 采用 C++ 框架在大型项目中管理依赖关系和集成问题

    在大型 c++++ 项目中,框架提供了以下工具管理依赖关系和集成:依赖关系管理使用包管理系统(如 cmake、conan)定义和自动化依赖项的下载、构建和安装。集成遵循特定步骤和惯例,如分层架构,实现组件松耦合和简化通信。通过使用这些工具,团队可以高效地构建和维护大型、模块化的 c++ 项目。 在大…

    2025年12月18日
    000
  • 使用 C++ 框架构建大型项目的关键考量和最佳实践

    构建大型 c++++ 项目时,使用框架至关重要。关键考量因素包括选择合适的框架、模块化设计、代码复用和依赖管理。最佳实践包括遵守框架约定、使用框架工具、创建扩展点、文档化代码和实施持续集成与交付。遵循这些指导原则可创建坚实的基础,并交付满足用户需求的可靠且可维护的软件。 使用 C++ 框架构建大型项…

    2025年12月18日
    000
  • 揭秘 C++ 框架的盲点:解决隐藏问题

    c++++ 框架的隐藏问题:依赖关系、代码生成、接口依赖、性能瓶颈和调试问题,可通过查找文档、隔离问题、深入源码、使用调试器和寻求专业帮助解决。 揭秘 C++ 框架的盲点:解决隐藏问题 在 C++ 开发中,框架已成为提高生产力、可复用性和代码质量的重要工具。然而,当框架隐藏了实现细节时,也可能会带来…

    2025年12月18日
    000
  • C++ 框架与设计模式的协同效应

    c++++ 框架和设计模式相结合,通过代码重用、一致性和可扩展性提高了开发效率和代码质量。设计模式提供了可重复且通用的解决方案,增强了框架组件的开发和使用,而框架为设计模式提供额外的功能和指导其开发。 C++ 框架与设计模式的协同效应 引言 C++ 框架和设计模式是软件开发中不可或缺的工具。框架提供…

    2025年12月18日
    000

发表回复

登录后才能评论
关注微信