阅读视图

发现新文章,点击刷新页面。
🔲 ☆

NVIDIA 为 CUDA 添加原生 Python 支持:开启 GPU 计算新篇章

引言

在最近的 GTC 大会上,NVIDIA 宣布为其 CUDA 工具包引入原生 Python 支持,这一举措可能彻底改变 Python 开发者使用 GPU 计算的方式。作为全球最流行的编程语言之一,Python 在数据科学、机器学习和科学计算领域的广泛应用促使了这一更新。NVIDIA 此举不仅降低了 GPU 编程的门槛,还可能进一步推动其在全球开发者社区中的普及,尤其是在印度和巴西等发展中国家。

背景

CUDA 是 NVIDIA 推出的并行计算平台,旨在加速各种计算任务。自 2020 年以来,CUDA 的用户数量从 200 万激增至 2023 年的 400 万,显示出其在开发者中的日益重要性。与此同时,根据 GitHub Blog: Octoverse 2024 Analysis 的数据,Python 在 2024 年超越 JavaScript,成为最受欢迎的编程语言。这一趋势为 NVIDIA 提供了契机,通过整合 Python 支持来吸引更多开发者,尤其是那些习惯使用 Python 进行数据分析和 AI 开发的群体。

CUDA Python 的新功能

NVIDIA 为 CUDA Python 引入了一系列新功能,旨在提升开发效率并简化 GPU 编程:

  • 即时编译(JIT Compilation)
    JIT 编译减少了代码的依赖性,使开发者能够更轻松地管理和部署项目。通过在运行时动态编译代码,这一功能还能提升性能,减少对预编译二进制文件的需求。
  • CUDA Core
    被描述为“Python 风格的 CUDA 运行时重新设计”,CUDA Core 为 Python 开发者提供了更直观的接口来管理 GPU 资源。这对于不熟悉传统 GPU 编程的用户来说尤为友好。
  • NVMath Python
    该组件统一了主机(CPU)和设备(GPU)的库调用,简化了跨架构的代码开发。对于需要在 CPU 和 GPU 之间切换的应用程序,这大大提高了开发效率。
  • cuPyNumeric
    cuPyNumeric 是 NumPy 的 GPU 加速替代品。根据 NVIDIA Developer: cuPyNumeric Overview 的介绍,开发者只需更改 import 语句,就能将现有的 NumPy 代码迁移到 GPU 上运行。这一功能基于 Legate 框架,支持从单 CPU 系统扩展到多节点多 GPU 集群,特别适合处理大规模数据集的研究人员和数据科学家。
  • CuTile
    CuTile 是一种专注于数组级处理的新编程模型,旨在简化 GPU 计算的编码和调试工作。目前它主要为 Python 开发,未来计划扩展到 C++,以覆盖更广泛的开发者群体。

技术细节与支持库

CUDA Python 还包括一些增强功能的组件:

  • cuda.core:提供对 CUDA 运行时和核心功能的 Python 风格访问。
  • cuda.bindings:为高级用户提供对 CUDA C API 的低级 Python 绑定。
  • cuda.cooperative:支持高效的并行算法,如排序、扫描、归约和变换。
  • cuda.parallel:为 Numba CUDA 内核提供 CUB 的块级和线程级原语。

此外,nvmath-python 提供了 CPU 和 GPU 的数学库支持,进一步丰富了科学计算的生态系统。

潜在影响

这一更新有望显著降低 Python 开发者使用 GPU 的门槛,尤其是在数据科学、人工智能和科学模拟等领域。cuPyNumeric 使 NumPy 代码无需大幅修改即可扩展到 GPU 集群,这可能彻底改变研究人员处理大规模数据问题的方式。例如,计算流体力学、机器学习模型训练和高能物理等应用都将受益于更快的处理速度。对于发展中国家而言,Python 的易用性结合 CUDA 的强大性能,可能推动高性能计算资源的普及。NVIDIA 的这一战略不仅提升了开发者的生产力,还可能在全球范围内激发更多创新。

结论

NVIDIA 为 CUDA 添加原生 Python 支持是对 Python 在计算领域日益增长需求的积极回应。通过引入 JIT 编译、CUDA Core、NVMath Python、cuPyNumeric 和 CuTile 等功能,NVIDIA 不仅简化了 GPU 编程,还扩大了其潜在用户群。这一发展有望赋能新一代开发者,尤其是发展中国家的技术人才,让他们能够利用 GPU 的强大能力开发尖端应用。随着生态系统的不断完善,例如 CuTile 未来对 C++ 的支持,GPU 计算的普及性和多功能性将进一步提升。

参考资料

相关阅读:

🔲 ⭐

介绍一个生产力工具:ntfy

之前为了监控家里的IP地址的变化,写了一个循环任务,每隔几秒钟访问一次ifconfig.io,获取大网IP,当发现IP地址变化时,通过mailgun发邮件到自己邮箱,用这种方式感知到IP地址变化,同时也使用域名提供商的域名解析接口刷新IP地址。这个邮箱通知的方式有点偏重,并且mailgun随时有被墙的风险。最近开始接触虚拟币投资,发现虚拟币的波动大,适合短线交易。合约支持看空和看涨,因此只要有交易量,价格有波动则适合买卖,当然能否踩准加仓和平仓的波峰波谷才是关键。对于我这样每天并不能随时看盘的上班族而言,希望有个后台监控任务,识别已经仓位变化,变化幅度大时通知到手机。全网搜刮,找到了ntfy这个应用,支持自托管,有域名即可。用docker部署了,然后也下载了官方提供的android app,设置app后台常驻,使用方法也相当简单。直接上代码:

class Notify:
    def __init__(self, endpoint, user, password):
        self.auth_header = "Basic " + base64.b64encode(
            (user + ":" + password).encode("ascii")
        ).decode("ascii")
        # Remove trailing slashes
        while endpoint.endswith('/'):
            endpoint = endpoint[:-1]
        self.endpoint = endpoint

    def notify(self, title, msg, subject):
        if len(self.endpoint) == 0:
            return

        hostname = socket.gethostname()
        msg += f" (from {hostname})"
        res = requests.post(self.get_endpoint(subject),
                            data=msg,
                            headers={
                                "Title": title,
                                "Authorization": self.auth_header
                            })
        if not res or res.status_code != 200:
            logging.error(title)
            logging.error(msg)
            logging.error(str(res.status_code) + ":" + str(res.content))

    def get_endpoint(self, subject):
        if subject.startswith('/'):
            return self.endpoint + subject
        else:
            return self.endpoint + "/" + subject

然后就是调用币安的API SDK代码,请求账号的仓位信息,发现仓位变化量达到一定幅度时发通知。区分盈利和亏损,手机app上面分别订阅盈利和亏损的topic,设置不同的提示铃声,随时感知仓位变化信息,必要时进行平仓和加仓。

Screenshot_20241224_215317_ntfy Screenshot_20241224_215323_ntfy

后面基于这个代码继续丰富这个后台任务的逻辑,走上虚拟币量化之路。

🔲 ☆

困扰了快1个月的家用宽带网络卡顿问题-Linux病毒实战手记

最近一段时间家里领导反馈网络经常慢,之前还没太在意,上周反馈给电信,电信小哥直接给换了光猫。观察了几天,仍然间歇性的卡顿。尝试换路由器,换光猫拨号,都没有彻底解决。今天发现homenas流量异常,经常跑出大于电信宽带规格的带宽,家里宽带规格是300Mb的,上行更是只有50Mb的,怎么能跑出1000Mb带宽的数据量,很像是局域网的访问行为,这个带宽看起来很像家用磁盘的规格。压根没往外网流量上面想。查各种监控,都只有带宽和流出数据量的统计,找不到哪个进程或者业务。尝试atop,ntop,iftop,netdata,nethogs各种监控,都看不到流量哪里来的,更别说netstat了。最后只能tcpdump持续抓包,找到了一些线索。

​大量从本机发出去的syn包,syn flood攻击,只是我的nas是攻击方,被拿来做“肉鸡”了。只发出了syn包,netstat看不到连接,还是我敲命令的时候,攻击已经停了,应该是前者,攻击的时候,登录在控制台界面也看不到连接。发现所有的网络统计工具都不显示只发了syn包的连接。syn攻击在工作中经常听到,但是很少有机会去实地解决,前端的防护设备帮挡住了,没想到在家用设备上面遇到了。

​进一步找系统日志,有提示被攻击,应该是对端回应syn的包被系统识别为攻击请求直接拒绝了。
mmexport1713540039729

mmexport1713540042770

mmexport1713540047007

mmexport1713540048592
​第一天就先查到这里了,担心NAS上面的数据被破坏,也先保家里的网络,关机收工。留下了几个疑点:
​1,能跑出80MB上行带宽,远大于5MB,说明电信在这种攻击报文的带宽统计有缺陷,拦不住。当然syn包是否都出了光猫,发到了目标端,还是存疑的;
​2,操作系统能拦截外面进来的攻击行为,不知道有没有拦截本机外发攻击包的行为;
​3,根因应该是nas上面docker滥装,没有考证安全性,被留了后门,或者某个软件有已知的漏洞,被利用了。空了再找吧。

​第二天上午,小心翼翼的开启NAS,继续分析头一天的抓包和系统日志。

试图从日志搜索攻击目标端的IP地址是什么时候注入的,无果。然后逐行分析日志,将重复的UFW日志过滤掉。可以发现有两条Cron的日志一直在打印:

image

这条 /.mod的日志特别显眼,之前就看到过这个日志,没有联想到系统的异常流量,因此觉得就是系统的例行任务。现在仔细看这个文件,是放在根目录的,之前没去分析过这条记录的含义,没注意放在根目录。一般可执行的命令怎么会放在根目录?赶紧去根目录找这个文件,使用ls命令,居然是返回的空,没见过这种,大概率是修改了文件属性之类的,继续使用stat命令,就发现异常了。文件是3月30号创建的。考虑这个文件每分钟都在执行,那我手动执行一次也无妨。使用strace跟踪执行过程,发现这个可执行文件会去打开/usr/lib/libgdi.so.0.8.2这个文件,然后看起来是直接执行这个文件。这是so文件,怎么会可执行呢?病毒无疑了。后面去打开这个文件,才发现是一个脚本。比我想象的简单多了,相当于分析了一下shell脚本执行时的strace,:-(

看到这里震惊了,Linux系统出现病毒文件,并且还能对外发起syn flood攻击。一下子就明了了。这个so文件也是3月30号创建的,然后也尝试执行了一下,strace日志比较复杂,有大量的网络操作。剩下的就没细看了,直接Google,找到了非常接近的介绍:Linux.Siggen.5802,按照这里给的列表,逐一确认是否病毒文件,逐一删除,并清理掉病毒生成的Cron任务。

最后还想找到3月30号系统是如何安装上这个病毒的,找了系统日志,没有发现太大的异常,不知道跟下面这个是否有关系,好像早先折腾过UI界面的桌面环境,不知道是不是当时下载了非标的安装包带入的:

image

不管了,这个也一并卸载了。

最后网络终于恢复宁静了。总结一下,就是syn flood包把光猫或者路由器的带宽和连接资源耗尽,然后NAS自己的网络也占满,最终导致终端上网异常。我是在NAS上面部署了dnsmasq作为局域网的解析,因此有时候还表现为终端能用聊天软件,而不能打开网页。

其实中途,一度怀疑新买的Wifi6路由器不稳定,考虑弄一个二手的企业路由器拨号看看,找到了tplink r473g,还打开了调试模式,登录到路由器的shell里面,尝试用top+nc,把实时的top命令结果传出来,最终也确实有所发现,就是当网络异常时,路由器的CPU是满的,然后CPU用在soft irq上面,就是在不停的响应网络中断,看到这里也没什么头绪。当时就想在路由器上面抓包,但是busybox系统没有默认带这个,也没有curl等命令能把抓包数据传出去,难度有点大,就先放弃了,直到这周五发现HomeNAS经常有流量尖峰,才朝着HomeNAS上面去定位流量异常的这个方向走。最早是考虑局域网内的终端访问NAS带来的,逐个排查是哪个终端导致的,甚至二分法逐一关闭容器,都无果。最终还是抓包+系统日志找到了问题。HomeNAS上面,一般是用docker,很少安装不明二进制包,偶尔安装不明的来源的docker镜像。docker里面搞破坏应该很少能破坏宿主机。目前看来,这个病毒做得还不算绝,没有动系统文件,估计也怕jc抓。计算机世界的病毒跟自然界一样,都是希望跟宿主和谐共处,薅一点资源生存。以前只听说黑客利用系统漏洞,做一些攻击,也一直认为Linux很安全,没什么病毒。第一次经历Linux系统被植入病毒木马,上了重要的一课。

附:一些定位过程中的命令
接收远端日志:(nc -l 12599 -k >> router_log.txt &)
路由器跟踪top:(top –n 1 –d 3 |nc –v 22.22.22.3 12599 &),具体的循环任务忘记了,路由器的top没有打印时间,需要定时增加时间信息输出。
持续抓包:(tcpdump -i eno1  ‘not port 6870 and not port 22 and not port 443’ -s 96 -w all.cap -C 300 &)
iftop持续跟踪系统连接:(while :; do echo `date`>>iftop_all.txt; iftop -t -BNPn -s 10 -o 10s -i eno1 2>/dev/null >> iftop_all.txt; done &)
使用ntopng监控系统网络事件,使用iftop命令监控,跟Prometheus+Grafana的结果差不多,仅仅多了基于连接的统计结果。但是这种半连接过程的数据没有统计。

🔲 ⭐

『冲上云霄2』观后

周五看到这个高清版出来了,第一时间下载观看。剧情简单,场面宏大,战机的各种镜头堪称同类电影的天花板。总之,如果国内上映,去影院巨幕观看,应该是一场视听盛宴。

作为步入中年的程序员大头兵,感叹路越走越窄,没有搞定所有人都认为不可能的事情的本事,真的是要穷途末路了。老兵不在于用什么工具,重要的是过硬的职业素养,身经百战的实战经验。实战比理论重要。

这次在政治正确这块,只以中东某国为假想敌,不再拿北极熊开玩笑。该假想敌国拥有五代战机同时还有老旧的F14,正在发展铀浓缩技术。特地查了一下,还真属实,该国有F14A,政治国际关系就是这么风云变幻,昔日盟友今天的死敌。

Screenshot_20220821_195316_com.douban.frodo_-987x2048

无相关文章。

🔲 ⭐

Home NAS 音乐服务解决方案

之前写过使用《使用Emby + Picard管理音乐》的方案,Emby有一个问题,在划词搜索方面,必须前缀或者整词完整匹配,对于港台音乐名和元数据多是繁体字,用简体搜索时,无法匹配,一直希望能够模糊匹配,发现airsonic-advance这方面没问题,完美解决搜索问题。

EMBY简繁体搜索结果:

emby-1  emby-2

Airsonic-advance的搜索结果,可以看出是模糊匹配的,如果用繁体,当然能精确匹配会更好。

airsonic-1

服务端软件,除了Emby之外,也试用过Navidrome,功能差不多。其实目前各个音乐解决方案功能都大同小异,基本功能都是播放列表、加星标记、乱序播放、歌曲搜索、收藏和分享等。另外airsonic有部分英文歌曲能抓取歌词,中文的一般都抓取不到。所以服务端的差异点就在易用性和浏览器UI界面美观上面。对比之下,还是觉得airsonic-advanced更稳定,可选客户端多。

对于手机端,airsonic的适配更丰富,毕竟已经快形成接口规范了。一众Android客户端都有体验一下。

如下3个界面截图,依次是substreamerSubsonicUltrasonic,推荐度为substreamer>Subsonic>Ultrasonic。开源软件都有一个问题,界面实在简陋,话说,免费能有的用就不错了 :)。

substreamer Subsonic Ultrasonic

另外也推荐一个处理CD文件和各种转码的工具,EZ CD Audio Converter,几乎能识别和转换所有格式,同时针对专辑文件,还能从多个音乐库抓取元信息。相比于Emby + Picard更灵活好用。

总的来说推荐如下组合搭建自己的音乐库:服务端airsonic-advance,客户端substreamer,工具,单曲元数据抓取:Picard,CD抓轨:EZ CD Audio Converter。再也不用担心XX云音乐动辄搜藏好的歌曲变为收费无法播放了[坏笑]。

🔲 ☆

关于父子进程信号传递、Shell进程退出等问题

我们通常都有这样的经历,用shell启动一个业务运行着,在终端界面上按下ctrl+c后,发现还有脚本启动的后台任务仍在运行。或者是出现另外一个方面的问题,本来希望进程安全在后台运行,退出了当前界面后,后台进程也跟着退了。关于这里第2个问题,之前有一篇博客讨论过:让进程在后台可靠运行的几种方法。今天我们探讨第1个问题,怎么让父进程(主shell脚本)退出时子进程(shell脚本中启动的所有后台任务)也退出。

我们知道当子进程退出时,父进程会收到子进程退出时发送的信号,进而做一些处理,如,父进程为守护进程的话,会重新拉起新的子进程。在shell中,我们一般使用wait命令来等待所有当前上下文中启动的后台任务。因此做如下实验脚本。

a1.sh是主脚本,在脚本里面使用后台运行的方式启动两个子任务:

root@shentar-home-nas:~# cat a1.sh
#!/bin/bash

bash b1.sh child1 &
cpid="$!"
bash b1.sh child2 &
cpid2="$!"

wait

b1.sh脚本用循环sleep模拟并行运行的子任务:

root@shentar-home-nas:~# cat b1.sh
#!/bin/bash

echo "$1 is starting"

while :
do
        sleep 1
done

执行a1.sh脚本后,效果如下:

root@shentar-home-nas:~# sh a1.sh
child2 is starting
child1 is starting

我们可以看到两个子任务并发启动。形成的进程树如下:

root     1591487  0.0  0.1  13996  8708 ?        Ss   10:14   0:00  \_ sshd: root@pts/0
root     1592132  0.0  0.0   8556  5392 pts/0    Ss   10:14   0:00  |   \_ -bash
root     1597850  0.0  0.0   2608   544 pts/0    S+   10:30   0:00  |       \_ sh a1.sh
root     1597851  0.0  0.0   7024  3432 pts/0    S+   10:30   0:00  |           \_ bash b1.sh child1
root     1598080  0.0  0.0   5476   596 pts/0    S+   10:31   0:00  |           |   \_ sleep 1
root     1597852  0.0  0.0   7024  3436 pts/0    S+   10:30   0:00  |           \_ bash b1.sh child2
root     1598079  0.0  0.0   5476   592 pts/0    S+   10:31   0:00  |               \_ sleep 1

如果我们杀死a1.sh进程(1597850)这个进程,那么两个子进程会怎么样呢?会不会跟着一起退出?普通的shell程序退出的条件是有异常循环终止或者进程收到1、2、15等信号。这里父进程退出并不会给子进程发送信号。当然,有一种情况,当登录当前TTY的用户注销时,所有由当前终端启动的前后台进程都会收到SIGHUP信号,一般程序收到此信号即退出运行。但是普通的父子进程并不这么做。所以当a1.sh进程退出后,b1.sh的两个子进程不会跟着退出,会被进程ID为1的进程接管,成为孤子进程。那么,如果我们希望主脚本退出时,所有子进程都依次退出该怎么做呢?

应该在主进程里面捕获常见的退出信号,然后在信号处理流程里面给子进程发送退出信号。使用trap命令可以在shell脚本中捕捉信号,注意trap对于同一个信号可以在任何地方捕捉,最终运行的回调函数以最后一次为准。对a1.sh进行一些改造:

root@shentar-home-nas:~# cat a.sh
#!/bin/bash

bash c.sh child1 &
cpid="$!"
bash c.sh child2 &
cpid2="$!"

trap 'echo "get sigint"; kill -15 $cpid;wait $cpid; sleep 3;kill -15 $cpid2; wait $cpid2' 1 2 15

wait
echo "all childs exited"
为了更清楚的看到子进程捕获信号的过程,我们对子进程也增加一些信号处理过程。
root@shentar-home-nas:~# cat c.sh
#!/bin/bash

trap 'echo "got sighup"' HUP
trap 'echo "got sigint"' INT
trap 'echo "got sigquit"' QUIT
trap 'echo "got sigkill"' KILL
trap 'echo "got sigterm"; echo "$1 exit";exit 0' TERM
trap 'echo "got sigtstp"' TSTP
trap 'echo "got sigconf"' CONT

echo $1


while :
do
        sleep 1
done

这样,当我们使用ctrl+c退出主进程时,就会发生触发两个子进程也都退出的过程。

root@shentar-home-nas:~# sh a.sh
child1
child2
^Cget sigint
got sigterm
child1 exit
got sigterm
child2 exit
all childs exited

通过捕获信号,我们还可以实现进程不响应ctrl+c或者TERM信号的实现,即可以达到程序安全的常驻内存运行的目的。nohup,disown等都是这个原理。

🔲 ⭐

jAlbum升级JDK、Jetty和支持HTTP2

利用这个周六休息时间,将jAlbum代码升级了下。主要是想支持HTTP2,提升浏览器加载性能。升级过程中遇到一些问题,记录下:

1、alpn库的问题,jetty在配套不同的jdk版本时,有一些策略:见官网链接的说明:Jetty 9 and ALPN,jdk8使用一个单独的包,jdk9及以后的版本使用使用alpn的api,需要另外一个包。在不同的jdk环境下,依赖包有差异,不能混淆。

2、jar-with-dependencies 和 META-INF/services 冲突的问题。大概是jetty-http和jetty-http2包内都实现了同一个接口,而jvm只加载到了其中一个:
org.eclipse.jetty.http.Http1FieldPreEncoder
org.eclipse.jetty.http2.hpack.HpackFieldPreEncode
两个类都实现了同一个接口,使用了META-INF/servcies目录的机制。由于之前打包时,使用了将所有依赖包都抽取到一个独立jar包的做法,导致这个servcies目录下的同名文件只保留一个,最终http2的类无法加载成功。改用依赖包放在单独目录的方式,解决问题。

3、升级jdk到11之后,有几个原本是jdk自带的工具包(jaxb和anonations)被新版本jdk删除了,只能一一重新在pom.xml中添加回来。

本来支持http2是个比较简单的事情,由于这些库之间的互相依赖,折腾了比较久。具体修改:Commit记录。也编译了0.3.2版本放在版本下载表中。升级改造之后jAlbum、本站以及相关的子站点都全面支持HTTP2。

❌