2024年3月

让媒资中“沉默的大多数”再次焕发光彩。

邹娟|
演讲者

编者按

AIGC时代下,媒体内容生产领域随着AI的出现也涌现出更多的变化与挑战。面对AI的巨大冲击,如何优化或重构媒体内容生产技术架构?在多样的应用场景中媒体内容生产技术又有着怎样的实践效果?LiveVideoStackCon2023深圳站邀请到阿里云智能资深技术专家邹娟,与大家分享阿里云视频云的媒体内容生产技术实践。

策划 撰写 / LiveVideoStack、IMMENSE

《AIGC时代下阿里云视频云媒体内容生产技术实践》主题分享,包含如下四个部分:

01 AIGC时代的媒体内容生产技术架构

首先给大家分享阿里云视频云媒体服务的顶层架构设计,这为AIGC的快速落地奠定了基础。媒体服务整体架构分三层。

最底层是云原生底座,阿里云视频云构架在分布式云原生框架之上
,视频云与我们的客户一样,自身也是云的使用者,可以获得云计算IaaS层弹性、按需按量、规模化的红利。

中间层为
媒体基础层,即媒体服务的底层技术核心

这一层分为三个部分:左侧的算法区域包括音视频编解码与增强算法、特效渲染算法、视觉AI算法、3A算法等。中间的媒体引擎是执行各类媒体处理任务、AI任务的发动机,负责集成算法及工程优化,设计统一的媒体处理框架,实现媒体处理Pipeline的高质量运行。最右侧为媒体计算调度,与媒体引擎紧密配合,把不同类型的媒体任务调度到最合适的集群和机器上,形成性能、画质、成本的综合最优解。

顶层为阿里云视频云提供的PaaS媒体服务——PaaS服务层
,媒体服务PaaS以媒体内容生产为核心,其产物自然也是媒体内容消费的输入。例如转码输出的多格式多码率文件/流,大多为播放服务。PaaS服务层的模块划分思路即按照音视频生产消费的数据流向及模块依赖关系,划分为音视频采集-媒体处理-生产制作-媒资管理-媒体消费5个部分,其中“媒体汇聚”代表入方向,“媒体消费”代表出方向,“媒体处理”和“生产制作”用于媒体数据的内部处理和二创,“媒资”则是媒体数据/业务流程/生命周期策略管理的底座。

image

早在2017年,阿里云视频云就提供了视频AI相关服务,比如智能封面、视频DNA、智能审核等,那时这些服务以原子能力的形式提供,独立于视频云的媒体处理、生产制作、媒资服务之外。但随着AI能力的丰富,很多AI服务的输出产物就是音视频(比如视频集锦),或者需要与媒体处理同步进行才能有更好的效果(比如视频旧字幕擦除后叠加新字幕)。

因此技术架构迭代的第一步就是考虑媒体底层的AI能力融合。AIGC时代,媒体底层需要灵活融合各种AI能力,这种融合并不是业务层工作流的Activity编排,这样一般会引入多次编解码,带来画质与性能的损耗。我们选择把AI处理直接融入音视频处理pipeline,在Frame层面做最细颗粒度的编排。

回归到媒体业务流本身,在AI时代下,媒体服务PaaS可以在哪些方面优化?其实媒体业务流本身没有太大变化,变化的核心是使用了AI,希望AI能够模拟人类的思维,包括理解人的意图以及正确执行人的指令。当技术发展到一定程度,AI可以模拟人类的思维模式,场景就会被重构。阿里云视频云技术架构的迭代也会围绕这一思路展开。

image

阿里云视频云媒体内容生产技术架构在AIGC时代的迭代,也将从内容生产的三驾马车--
媒体生产制作、媒资管理、媒体处理
三个板块开展。

生产制作板块,我们的迭代方向是
从单个制作环节使用AI技术转向全智能制作
。除创意依赖人之外,AI可以参与到生产制作的其他环节,包括素材的挑选和生成、时间线的制作编排、以及效果渲染的大模型算法优化。

媒资板块的传统实现需要较多人工投入,例如专业媒体机构的编目软件需要大量人工编目数据录入的工作,阿里云视频云设计的
新一代媒资系统
能够像人一样理解媒资内容,使用自然语言进行搜索与管理,并为下一步的挖掘与图谱分析打下基础。

媒体处理的迭代方向聚焦于
效果的极致优化
。媒体处理可以抽象为单入单出的模型,基于此模型实现最大程度的效果优化,包括高清晰度的增强场景,低清晰度的重生场景,使用音频的双声道设备获得全景声或环绕声效果的场景等。

文章前面提到,媒体任务的最终执行会收口到媒体引擎层,这需要媒体引擎把AI处理融入媒体处理Pipeline。随着AI能力的日渐丰富,阿里云视频云的媒体引擎也进行了架构优化与技术升级,在AIGC爆发前完成了媒体底座的迭代,成为融合AI与媒体处理的一体化媒体引擎,为视频云快速引入并落地大模型算法节约了时间,接下来将分享一体化媒体引擎的关键技术。

02 融合AI与媒体处理一体化媒体引擎关键技术

image

大模型的引入带来庞大的算力消耗,对媒体引擎性能的挑战尤为突出,我们设计的高性能智能媒体引擎的要点总结为以下三个方面:

第一,架构方面,做分布式处理,提高多机并行
。这里的分布式处理并非表示将海量任务分布式调度到不同机器,而是指单个任务的分布式处理架构。当任务的复杂度较高时,将其不同环节分散到不同的机器上,解决单机无法满足任务算力的问题,或者任务的特定环节需要指定机型的问题。

第二,进程方面,统一pipeline
。视频云的ToB模式,要求我们支持不同客户的多种场景和应用,统一pipeline可以减少各场景的计算冗余,同时对底层算法库和媒体处理框架的统一则让引擎层执行不同任务具有更好的鲁棒性。

第三,算法方面,阿里云视频云实现软硬一体的优化
,通过CPU、GPU以及AISC编解码加速,支持云上各时期的多种机型规格,同时从算法和工程两个维度优化单帧处理性能,在大模型算力紧张的时代最大程度的利用现有算力。

image

以单任务分布式处理——超高清视频AI处理为例,1080P超分到4K使用了深度学习算法,那么将该任务调度到高配GPU机器上运行,可能会导致机器的CPU空闲而不利于资源的整体利用。阿里云视频云的媒体引擎支持对单任务进行分布式处理,可以将解码、前处理、编码、Merge放在不同的机器执行,也可以将单任务切片成多个子任务再进行分布式处理。比如超分处理可以放在GPU的机器上,解码、编码以及Merge可以调度到另外的集群,对于是帧级别传输的场景,媒体引擎会在pipeline内部进行媒体数据的YUV交换和无损压缩,从而实现单任务多环节计算资源的最优搭配。

image

媒体引擎会接收到各种各样的媒体计算任务,接上一个技术点“单任务的分布式处理”继续探讨,如何判断哪些任务需要走分布式,哪些任务单机执行反而效率最高呢?阿里云视频云媒体引擎设计并实现了Worker-Brain决策大脑,对单任务消耗的资源做精准预估,自动判断进程和算子所需机型,对任务是否切片和算子编排流程进行决策,同时在任务执行时自动根据算法复杂度进行升降机,消除cpu毛刺,实现稳定性自保护机制。

另外,阿里云视频云
在媒体引擎层统一了媒体处理任务框架
。由于直播、点播、生产制作以及云剪辑等业务的发展阶段不一样,存在算法依赖库不统一或版本不一致的历史问题。媒体引擎将自研算法依赖版本进行了统一,用相同的媒体处理框架支持不用的任务类型,甚至在一些版本上实现云和端的统一。宏观来讲,阿里云视频云将各种业务资源并池,不同的业务共用异构的资源池,资源池之间也可互备来保证整体服务的稳定。

image

这是综合应用“单任务分布式处理”和“Work-Brain智能决策”的全智能媒体处理引擎实践,以“数字人抠像并且将其与云剪辑融合”的场景为例,左边是素材和时间线涉及的原材料,时间线可能需要对素材做ASR,同时还存在数字人的生成与同步、人声克隆、抠像背景替换、画质增强等要求。整个任务相当复杂,且涉及多个算子,通过Worker-Brain进行资源评估后,该任务既需要将pipeline的不同环节拆到不同的机型执行,进行单任务分布式处理,也需要将长视频切片,对任务进行并行处理。而另一个标准转码任务(比如单入单出1080p 264转480p 264)经过Worker-Brain决策后,在单机完成整个任务的执行是最优的。

image

最后分享软硬一体的异构计算。CPU加速相对比较传统,涉及多线程的帧间优化、帧内优化、指令集优化以及数据读写优化。结合到AI异构场景下,经常需要考虑CPU与GPU之间的关系,以前大多选择一台CPU+GPU的机器完成整个任务,现在可以基于前面提到的架构,把单个AI任务分离,把CPU和GPU的部分调度到不同机器上处理再合并。

阿里云视频云还支持各种异构计算,包括CPU/GPU/AISC等,比如ASIC的硬解硬编需要平衡性能、画质、延时、成本等多种指标,还需要考虑稳定性因素,因为单台AISC服务器一般拥有更大的吞吐量,出现异常受影响的任务数更多,这时还需要考虑主备模版的兜底和任务的降级切换策略。因此媒体引擎层的异构计算需要统筹CPU、GPU、ASIC的算力和特性,将云端资源充分利用起来。

03 媒体内容生产AIGC技术实践

第三部分是阿里云视频云关于内容生产AIGC的技术实践。

image

在AIGC爆发前,用户已经开始使用AI,AI相关话题已经“火”了好几次,阿里云视频云的AI服务也上线超过6年。

此前用户更多是在单点环节使用AI,例如图上展示的生产制作和媒体处理的能力,在AIGC爆发前,许多厂家、开发者、创业者都使用过,此类能力大多针对特定场景,要进行规模化时,只能进行一些微调,如果不针对特定场景,则存在效果泛化性不够导致准召率不高的情况出现。

image

在AIGC时代到来后,阿里云视频云重新审视了媒体内容生产业务流程,
媒体处理/媒资/媒体处理三驾马车都值得用AI再度重构或优化

image

媒体处理的AIGC重构较多依赖于媒体引擎的底层技术
。各种架构的升级改造都是为了满足或迎合传统的音视频前处理与AI算法、编码器结合的场景,而前面提到的,媒体引擎的统一媒体处理框架和引擎架构优化,可以完全复用在AIGC时代,媒体任务在底层的执行,本质与前AI时代没有区别。

媒体处理PaaS服务层的重构设计则体现在API与流程编排上
。在API层面,阿里云视频云把AI和传统的媒体处理在媒体与管道协议上进行统一,这种统一不仅是协议层面的统一,也代表着底层调度资源可以进行混部或混合调度。关于流程编排,AI环节和媒体处理环节可以在相同的工作流引擎中自由编排。

媒体处理AIGC重构的核心在算法与媒体引擎的联合优化
。下面展示两个案例:

image

阿里云视频云用更精细的图像纹理细节提取方式,来进行细节修复和生成,算法优化的思路是还原图像的真实面貌,这与我们在2015年、2016年开始研发的窄带高清思路如出一辙。多年以来,这个方向一直没有变过,也比较契合许多行业和场景的诉求。

image

我们在4K超分+HDR超高清的实践,算法侧采用局部变化策略,使亮度更有层次感。展示案例对树木纹理的细节进行了增强,在色彩方面进行了调整优化。另外值得一提的是,此任务刚上线时处理速度非常慢,通过媒体引擎的单任务分布式框架,对任务切片并行处理后,最终的处理速度达到刚上线时的100倍,大大缩短了客户app发布高质量视频的周期。

image

阿里云视频云的媒资系统架构分为三层,分别是
媒体数据层、基础服务层和智能服务层

关于媒体数据层,我们大概在三年前将媒资的元数据体系重构为可灵活定义和组织的任意实体,可零代码接入AI生成的各类媒资元数据,同时实现了统一MediaID,支持视频云内部多产品的媒资互通。近一年对媒资索引进行了重构,将基于文本元数据的索引和基于特征值的向量索引整合起来,通过统一的API提供搜索服务。

关于媒资智能服务层,我们在媒体数据之上,采用多模态语义重构了媒资内容的结构化逻辑,采用自然语言搜索替代关键词搜索。这两项基础又可以应用到智能编目和智能资源管理模块,比如智能编目可以自动填充内容描述字段,以及根据内容结构化结果自动拆分片段;基于定向指令的搜索结果可以用于媒体资源之间的关联和聚类等。

image

image

内容理解是搜索的基础,在大模型之前的多模态内容理解,是将视觉信息、语音信息等都转换为文本,如视频画面内容识别为各种标签,语音识别为ASR文本等,视音频映射为文本本身就会造成信息的丢失,对近义词和同义词的扩展理解就更不敏感,无法真正从视音频维度理解语义。阿里云视频云在 9 月底上线了基于大模型的智能搜索,将视频的图、音、文统一到一个高维的向量空间中,避免语义损失。同时,搜索的文字也转化为高维向量,不再分词,与传统视频 AI 搜索相比,Top5 的准召率大幅提升。

搜索广泛应用于媒体服务的各个环节。除了媒体管理本身,制作素材的选择和时间轴素材的智能匹配也可以通过重组后的搜索服务获得更准确的结果。内容理解是搜索的基础,大模型之前的多模态内容理解,是将视觉信息、语音信息和其他信息均转换为文本,比如视频画面内容识别为各种标签,语音识别为ASR文本等,视觉和音频映射成文本本身就会造成信息的丢失,对于近义词、同义词的扩展理解就更加不敏感,无法真正从视觉和音频的维度理解语义。阿里云视频云在9月底上线了基于大模型的智能搜索,将视频的画面、音频和文本统一到一个高维向量空间,避免语义丢失。同时搜索的文本也转成高维向量,不再进行分词,相较于传统的视频AI搜索,Top5的准召率有明显提升。

搜索在媒体服务各板块都有广泛应用,除了媒资管理本身,生产制作的素材挑选和时间线素材智能匹配,也可以通过重构后的搜索服务获得更精准的结果。

image

image

阿里云视频云对于生产制作的顶层设计比媒资更早进行,早在2017年的第一版就考虑到了AI可能会参与到时间线Timeline的生产、编排和渲染中,因此第一张图的基础架构沿用至今。而这一轮的AIGC重构点主要有两个,1)AI完全融入时间线,例如在时间线的素材和效果定义中加入AI因子,即定义AI类型的素材(比如素材由AI生成)和AI类型的效果。2)实现了并行剪辑的智能分片策略,并提升了Timeline的可切分比例,以前Timeline Split点需要避开Timeline中的各种特效和循环素材,优化后,几乎兼容了95%的Timeline。智能分片策略则与媒体引擎的Worker-Brain配合,以时间线合成的时效性为目标,决策最优算子和流程编排。

接下来,会介绍几个已经在阿里云视频云生产制作产品应用AIGC技术的实践。

image

image

Case1:数字人剪辑
。这是目前AIGC商业化最成功的场景,数字人在视频制作、虚拟主播、在线教育和广告行业中,提供与真人难以区分的视觉、音频和互动体验,降低了内容生产的成本和时间,在实时场景可以不间断地工作,在非实时场景可以规模化生产,满足了全球市场定制化规模化生产Presentation视频的需求。

2023年10月底的云栖大会,央视采访并播出了题为《生成式大模型进军视频领域 “数字人”应用场景拓展》的报道,介绍了阿里云视频云的数字人剪辑技术和应用。阿里云视频云使用数字人剪辑技术,结合批量混剪timeline,采用不同的数字人形象渲染,接近真人语音的人声克隆,一小段文案,通义万相生成若干背景,多项技术共同配合,完成了视频的规模化生产。目前我们的不少客户使用这个方案减少真人主播的成本支出,提升成片制作的数量。

image

Case2:智能实时制作
。阿里云视频云基于大模型升级了云导播产品虚拟演播室场景的实景抠像效果,这次升级有三个核心点:第一,由原来的单层抠像升级为多层多实体抠像,既可以仅抠人像,也可以把人像连同部分物品抠除,保留需要的物品和背景;第二,抠像效果显著增强,体现在面对极为杂乱的背景(比如云栖大会展会现场),仍然在分割边缘有发丝级精度的效果,这将大大降低虚拟演播室的环境门槛,让随时随地的外场直播也可获得演播室的体验;第三,大模型对算力消耗较大,实时制作场景需要从算法到工程进行优化,以保证实时性,比如模型裁剪、大小模型结合改造、多线程优化等,这是大模型技术应用在直播及更低延时场景的必经之路。

image

Case3: 一键成片
。一键成片是阿里云云剪辑智能生产的综合应用,覆盖生产制作业务流程中,包括素材预挑选、片段截取、素材补充生成在内的素材准备与选取、智能时间线编排、效果包装、合成渲染等多个环节。AIGC在每个环节都可能发挥作用,比如基于多模态语义的视频搜索与摘要可用于素材预挑选,文生图或文生视频可用于素材的补充,数字人+人声复刻可用于配音和包装,支持AI与媒体处理帧级别编排的媒体引擎用于最终的合成渲染,这绝非单点算法、单个框架或者单项能力之功,而是AIGC技术与媒体服务多环节多层次融合的完整系统工程。

image

春节期间Sora爆火,突破了文生视频大模型以前只能生成几秒钟空镜头的固有印象。Sora有更深入的文本指令理解能力与互动能力,生成的镜头层次更多,内容更丰富,时长可达1分钟,以Sora为代表的新一代文生视频大模型,让AIGC距离完美成片更近一步。

回归生产制作的业务流本质,AIGC完美创作并生产成品,仍然需要经历创意、素材、编排、剪辑与包装、渲染与合成这几个阶段。目前几乎所有剪辑的“创意”仍然由人来主导,AI还无法自主进行原创,尤其是针对故事性视频的原创;“素材”则是AIGC深入贡献的环节,从已有素材的搜索、到各种文/图生图/视频、风格化带来的新素材、素材的修复与画面修改等,都有大模型的身影;基于大模型的技术在“剪辑包装”和“渲染合成”这两个环节提供较为散装的支持,整体仍以传统AI和标准剪辑技术渲染技术为主。总的来说,媒体内容的“素材”生产随着文生视频大模型的快速进展有了巨大的突破,但是“完美成片”的全智能生产制作仍然处在初级阶段,从另一角度看,这也代表AIGC未来在生产制作领域还有巨大的发展空间。

04 未来展望

image

当前AIGC的整体思路还是向人学习,下一步的发展可能会像人一样,以及在某些领域超越人,比如AIGC的效率在绝大多数场景下已经超越了人,而在思考力和决策力方面大多需要依赖人的反馈,以便进行持续优化。

如何创作内容有故事性、有质感的视频,是生产制作领域追求的目标。我们期待未来AI能够自行挖掘创意点,自主设计原创剧本,贯通前期拍摄和后期制作技术,生产出高质量的成片,而非仅仅生成空镜头或单镜头素材。AIGC用于媒体处理最直接的收益是音视频效果的增强,而在所有的增强场景中,电影修复无疑是难度较大的,要把老电影修复到还不错的状态,目前部分环节仍然需要人工参与。我们期待未来即便在电影修复场景,也能有更好的泛化性和更逼真的效果。在媒资领域,阿里云视频云希望建立一套自然语言理解的体系,实现媒体资源的多模态全语义理解,让媒资中“沉默的大多数”通过新一代的AI分析,语义挖掘、关联、图谱技术再次焕发光彩。

以上就是我的分享内容,谢谢大家。

前言

Microsoft Excel的XLSX格式以及基于文本的CSV(逗号分隔值)格式,是数据交换中常见的文件格式。应用程序通过实现对这些格式的读写支持,可以显著提升性能。在本文中,小编将为大家介绍如何在Java中以编程的方式将【比特币-美元】市场数据CSV文件转化为XLSX 文件。

具体操作步骤如下:

  1. 创建项目(使用intelliJ IDEA创建一个新的Maven项目)
  2. 查询数据(使用AlphaVantage Web服务获取CSV格式的月度BTC-USD数据)
  3. 加载CSV(使用GrapeCity Documents for Excel API)
  4. 处理CSV(重新排列列、创建表格并创建带有趋势线的图表)
  5. 返回XLSX(使用GrapeCity Documents for Excel API)

1)创建项目

(1)使用 Visual Studio 2022,创建一个新项目 ( CTRL+SHIFT+N ) 并 在下拉列表中 选择
C#

所有平台

WebAPI
,以快速找到项目类型ASP.NET Core Web API,然后选择它并单击 下一步。

(2)输入
BTC_Chart_WebService
作为 项目名称 并选择 项目的 位置,然后单击下一步。

(3)对于 Framework ,选择
.NET 6.0(长期支持)
或更高版本。在对话框中为其他配置选择默认值后,单击 “下一步”。

(4)这将创建一个模板 ASP.NET Core WebAPI 项目,其中包含返回天气预报的示例代码。我们的项目中不需要它,但我们可以重用和重新调整控制器的用途。

使用 解决方案资源管理器 ( CTRL+ALT+L ) 将项目中的控制器文件(在 Controllers下)重命名为
BTCChartController.cs

在 Controllers下,将 WeatherForecastController.cs 文件重命名为 BTCChartController.cs ,
当更改文件名时, Visual Studio 将提示您并询问您是否还要更改项目中的所有代码引用 - 在对话框中单击“是” :

然后在解决方案资源管理器 ( CTRL+ALT+L ) 中,右键单击 “依赖项” 并选择 “管理 NuGet 包”:

2)查询数据

创建一个CSV类,用于从AlphaVantage Web服务查询CSV格式的月度BTC-USD数据。小编在该类中创建一个getCsvData方法用于获取具体的数据(在代码中替换成你的API密钥即可):

// Get the CSV data from the AlphaVantage web service
private string GetCsvData()
{
    string csv;
    string API_KEY = "YOUR_KEY_HERE";
    string QUERY_URL = $"https://www.alphavantage.co/query?function=DIGITAL_CURRENCY_MONTHLY&symbol=BTC&market=USD&apikey={API_KEY}&datatype=csv";
    Uri queryUri = new Uri(QUERY_URL);
    using (HttpClient client = new HttpClient())
    {
        Task<string> t = client.GetStringAsync(queryUri);
        while (!t.IsCompleted)
            t.Wait();
        csv = t.Result;
    }
    return csv;
}

3)加载CSV

现在,将Get()方法的代码替换为以下代码片段。这会:

  • 将HttpGet属性 中的 Name更新 为
    GetBTC-USDChartWorkbook
  • 将返回类型更改为 FileContentResult,
  • 注释掉与天气预报相关的代码
  • 添加调用GetCsvData() 的代码 并将其导入到新 工作簿中

BTCChartController.Get

[HttpGet(Name = "GetBTC-USDChartWorkbook")]
//public IEnumerable<WeatherForecast> Get()
public FileContentResult Get()
{
    //return Enumerable.Range(1, 5).Select(index => new WeatherForecast
    //{
    //    Date = DateTime.Now.AddDays(index),
    //    TemperatureC = Random.Shared.Next(-20, 55),
    //    Summary = Summaries[Random.Shared.Next(Summaries.Length)]
    //})
    //.ToArray();
 
    // first get CSV data
    string csv = GetCsvData();
 
    // create new workbook
    IWorkbook wbk = new Workbook();
    // open CSV data in GcExcel using MemoryStream
    using (Stream s = new MemoryStream())
    {   // convert to byte array using UTF8 encoding
        byte[] arr = System.Text.Encoding.UTF8.GetBytes(csv.ToCharArray());
        s.Write(arr);
        s.Seek(0, SeekOrigin.Begin);
        // open CSV in workbook
        wbk.Open(s, OpenFileFormat.Csv);
    }

4)处理CSV

接下来,复制以下代码(在上一个代码片段中的
using
块之后)以处理 工作簿中的 CSV :

BTCChartController.Get(续)

public static void processWorkbook(Workbook workbook){
    IWorksheet worksheet = workbook.getWorksheets().get(0);
    // 把第K列数据移动到B列位置
    worksheet.getRange("B:B").insert();
    worksheet.getRange("K:K").copy(worksheet.getRange("B:B"));
    worksheet.getRange("K:K").delete();

    // 获取数据范围
    IRange usedRange = worksheet.getUsedRange();

    // 创建表格
    ITable addTable = worksheet.getTables().add(usedRange, true);
    addTable.setName("每月比特币数据");
    usedRange.autoFit();

    // 创建图表
    IShape iShape = worksheet.getShapes().addChart(ChartType.StockVOHLC, 0, 0, usedRange.getWidth(), usedRange.getHeight());
    IChart chart = iShape.getChart();
    chart.getChartTitle().setText("比特币每月开盘-最高-最低-收盘-成交量");
    chart.getSeriesCollection().add(worksheet.getRange(0,0,usedRange.getRowCount(),6), RowCol.Columns,true,true);
    IAxis categoryAxis  = chart.getAxes().item(AxisType.Category);
    categoryAxis.setBaseUnit(TimeUnit.Months);
    categoryAxis.getTickLabels().setOrientation(45);
    categoryAxis.getTickLabels().setNumberFormat("d/m/yyyy");

    ITrendline voltrend  = chart.getSeriesCollection().get(0).getTrendlines().add();
    voltrend.setName("3个月移动平均成交量");
    voltrend.setType(TrendlineType.MovingAvg);
    voltrend.setPeriod(3);
    voltrend.getFormat().getLine().getColor().setRGB(Color.GetBlue());
    voltrend.getFormat().getLine().setDashStyle(LineDashStyle.RoundDot);

    ITrendline hightrend  = chart.getSeriesCollection().get(2).getTrendlines().add();
    hightrend.setName("3个月移动平均最高价");
    hightrend.setType(TrendlineType.MovingAvg);
    hightrend.setPeriod(3);
    hightrend.getFormat().getLine().getColor().setRGB(Color.GetGreen());
    hightrend.getFormat().getLine().setDashStyle(LineDashStyle.RoundDot);

    ITrendline lowtrend  = chart.getSeriesCollection().get(3).getTrendlines().add();
    lowtrend.setName("3个月移动平均最低价");
    lowtrend.setType(TrendlineType.MovingAvg);
    lowtrend.setPeriod(3);
    lowtrend.getFormat().getLine().getColor().setRGB(Color.GetRed());
    lowtrend.getFormat().getLine().setDashStyle(LineDashStyle.RoundDot);
}

首先,代码获取 包含 CSV数据的IWorksheet ,并重新排列列以将 Volume 列放在 Date 和 Open列之间。然后,它创建一个 名为
BTC_Monthly
的表 ,其中包含 CSV 数据并自动调整 表中的列。

然后,代码在整个表格范围内添加一个StockVOHLC 类型的工作表 (成交量-开盘-高-低-收盘)新图表,设置图表标题,将系列添加到图表中,将类别轴单位更改为“月”,更新类别轴刻度标签方向和数字格式,然后创建三个 Trendlines。趋势线以蓝色显示成交量的三个月移动平均线 , 以绿色显示最高价,以 红色显示最低价。

5)返回XLSX

最后,创建一个Main类,并添加相关方法作为整个程序的入口,右键执行程序后就可以获得最终的Excel XLSX文件。

    // Save Workbook to XLSX and return from web service as "BTC_Chart.xlsx"
    using (MemoryStream ms = new MemoryStream())
    {
        wbk.Save(ms, SaveFileFormat.Xlsx);
        ms.Seek(0, SeekOrigin.Begin);
        byte[] bytes = ms.ToArray();
        return File(bytes, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "BTC_Chart.xlsx");
    }
} // Get()

运行结果如下所示:

总结

以上就是在C# 中以编程的方式将 CSV 转为 Excel XLSX 文件的全过程,如果您想了解更多信息,欢迎点击这篇
参考资料
访问。

作为一个即将年满30岁的程序员,如果用一句话总结我自己的2023年,这句话应该是什么?这个问题还真把我难住了。这一年是百感交集啊。纠结良久,我打算这样来总结我的2023:
平凡而满意的生活

累而不得的工作

再次起航的写作生涯
,当然还有
焦虑而迷茫的未来
。篇中更多是是我的
怨念总结
,各位看官别见笑啊!

平凡而满意的生活

首先是平凡而满意的生活。我的2023年,父母身体尚可;而我,有对象,感情和睦。作为北漂,我俩共同进行着人生的规划、完成着一件件大事小事。路虽坎坷,但是作为极其普通人来说,也算是满意。

生活好像和博客园的技术氛围不符合,这里省略1000字……

累而不得的工作

2023,后疫情时代的开端,经济周期的下行阶段,有人说活着就好,有稳定工作就好,而现阶段的我只想说:
宁可悲壮死,不愿苟且活

简单回首这一年的工作,可以说是累而不得。

经济下行阶段,裁员潮不断,有的人稳定且逆势生长,有人拿着N+1大礼包被裁,有人继续苟活着。我是苟活着的那一批人,相比苟活,我反而羡慕那些拿着大礼包昂首离开的同事,毕竟他们不但脱离了苦海,而且找到了更好的工作。

裁员对我们有什么影响呢?先想下裁员裁的是哪些人?裁员当然是多底层打工仔,小领导或者高管岿然不动。随着底层打工人的的一批一批的离开,干活的人员是越来越少。而老板在增长压力下开始各种折腾,想逆势而上,活是越来越多,那么未被裁员的反而成了更悲剧的群体,只能是越来越卷,真正实现了“
35711
”。何为35711,3个人干5个人的活,每周工作7天,每天11个小时。

35711听起来可能有点夸张,但有时候真是有过之而无不及。举个例子,遇到618或者6666661等大促压测,每次都要通宵干到凌晨六点左右,每个大促还得压测3次,而我这个“幸运儿”3次未缺席。羊毛可着一个人薅,怎能不累?全链路压测的时候在那有很多事情要做吗?其实不然,更多的时候是在陪跑,不陪跑行吗?不行!与其说是工作强度累,不然说是内耗使人心累。

在职场,如果有一件事情,每次都让人从满怀期待的希望,到失望,
最后到绝望,那便是晋升
。不管是公司晋升机制改革,还是“广进”计划和晋升名额缩减等客观因素影响,两年没有晋升和涨工资,上次晋升仿佛已经成为了远古的回忆。埋头干活就不该得到应有的尊重吗?为什么总是被选择性忘记呢?这肯定是存在问题的。

上学时读唐诗,学古文,我不懂为什么各个大诗人都是壮志未酬,郁郁不得志,读不懂那千古文字中的无奈。
艰难苦恨繁霜鬓,潦倒新停浊酒杯
。亲历毒打,我终究是听到了古人那遥远的呼声。用现在很火的一句话说就是:
教育终于完成了闭环

再次起航的写作生涯

面对累而不得的工作和失意的职场,我一定不能够被打败,我在想思考如何做一些提高自己事情呢?

那为什么不重新尝试一下写作呢?或许可以一试。我刚开始接触写技术博客是2018年左右,起初是为了记录和分享一些我学习和开发中遇到的问题或者小成果。后来听说这个算是找工作时的一个加分项,果断坚持到了找工作结束。

参加工作以后,工作是越来越卷,自由支配时间和写作时间越来越少,技术文章输出也逐渐枯竭甚至断流。其实我内心一直是有学习输入和写作输出的意愿的。在2023年底,一次偶然的机会,看到极客时间在筹备一个写作训练营。面对这个机会,再想想曾经的的“写作事业”,不多犹豫,索性报名参加了。

训练营时间不长,内容算是精彩。“
想都是问题,做才有答案
”,这是训练营的一句话,感觉还是挺有道理的。在训练营上面还有个感触就是,不要被完美主义打败。我之前有许多次的写作就是因为完美主义,本该进入“已发布”列表的,最终却停留在了“草稿箱”。

训练营结束之后,我逐渐在社区或者平台发布一些干货内容,重拾起来未竟的事业。还有这一年一度的年度总结,虽迟但到。加油吧,已经不再是少年的少年。

焦虑和迷茫的未来

世人慌慌张张,不过几两碎银
。我为何焦虑?硕士毕业马上四年,工资却不如普通应届毕业生,没钱成了我现在最大的焦虑。不光现在没钱,在能看到的将来也是如此。

焦虑其实就跟考试一样,这次考试没考好,如果我相信或者确定下次会考好,我是不会焦虑的。目前的情况就是,这次没考好,不相信、也不确定下次考试结果如何,与这次持平或者更差,这种情况只能是更加焦虑。再加上
35岁危机
已经在招手,作为一个
大龄低职级工程师
,升职和赚钱的窗口似乎已经渐渐关闭。

现实就是上面这样了,未来又该是什么样子的呢?

选择大于努力,选择对了方向,努力才有意义
。我该如何选择呢?如果选择继续在这里待下去,无异于坐以待毙。如我看到的,今天身边的那些大龄职级不高的工程师,就是我的明天。不破不立,如果选择换一个行业,换一家公司,那现在哪个行业处在风口?又该去往哪一个行业?哪一家公司呢?这些都是我正在思考的问题。

英国社会主义学家欧文曾提出了8小时工作,8小时休息,8小时自由支配的著名“
三八理论
”。除了工作,当然还有人生方面需要考虑。即将而立,最需要考虑的人生问题就是结婚;如何将工作和生活平衡,是另外一个问题。

这些问题互相影响,仿佛牵一发而动全身,也仿佛“剪不断,理还乱”。而最近,我也必须想清楚这些问题,定下基调和指导思想。我告诉我自己,冷静思考,细致分析,别着急。

最后

2024,我的而立之年,这一年是30-40岁阶段的开端。我感觉也是至关重要的一年,希望可以开一个好头,在来年总结的时候少一些怨念,多一分收获和豁达。也非常欢迎大家交流心得,共同进步。

问题背景

在你所不知道的端口耗尽前面的两篇章节中,介绍了经典的客户端端口耗尽和SNAT端口耗尽问题,但是对于解决方案只是一笔带过,这篇文章会更详细的介绍解决方案。解决方案主要分为两大类,优化部署和优化应用程序。

优化部署

本篇主要介绍在Azure上的部署以及主要是Azure集群的部署,针对的是SNAT端口耗尽问题。

Load Balancer增加前端IP

在(二)中详细介绍过,Load Balancer的每个前端IP可提供64K的端口,如果端口耗尽问题发生,最直接的方法是新增可用的IP。

Load Balancer调整出站规则

Load Balancer的默认出站规则是根据后端池大小分配 SNAT 端口。具体如下:

池大小(VM 实例) 默认 SNAT 端口
1-50 1,024
51-100 512
101-200 256
201-400 128
401-800 64
801-1,000 32

如果按照默认的出站规则,最大才1024,明显不符合大规模产品的需求,所以一般需要调整为手动端口分配,ports per instance。例如,若已知后端池中最多有 10 个 VM,则可以为每个 VM 最多分配 6,400(64000/10) 个 SNAT 端口,而不是默认的 1,024 个。

使用NAT网关

Azure 负载均衡器将固定数量的 SNAT 端口分配给后端池中的每个虚拟机实例。 这种分配方法可能会导致 SNAT 耗尽,尤其遇到流量模式不均衡导致特定虚拟机发送更高的传出连接量的情况。 与负载均衡器不同,NAT 网关在子网中的所有 VM 实例之间动态分配 SNAT 端口。

NAT 网关让子网中的每个实例都可以使用 SNAT 端口。 利用此动态分配,VM 实例可从可用端口池中使用每个实例所需数量的 SNAT 端口进行新连接。 动态分配可降低 SNAT 耗尽的风险

image

另外,NAT 网关从可用端口池中随机选择端口。 如果没有可用的端口,只要没有与同一目标公共 IP 和端口的现有连接,就会重复使用 SNAT 端口。 NAT 网关的此端口选择和重用行为使得遇到连接超时的可能性较低。

优化应用程序

重复使用连接

建议将应用程序配置为重复使用连接,而不是为每个请求生成单独的原子 TCP 连接。这里介绍一个最典型的例子,net core中的HttpClient,对外部网络的请求使用单instance或者使用HttpClientFactory,如果每个请求都构造一个HttpClient,那么即使同一目标公共 IP 和端口,也会分配不同的端口,这样端口很快就会消耗殆尽。

使用连接池

在应用程序中使用连接池方案,其在一组固定的连接中内部分布请求,并且在可能的情况下,重复使用这些请求。连接池一般存在于正在使用的框架中,所以技术选型和SDK时,一定要非常注意是否有连接池。

另外,也可以根据情况调整连接池的最大连接数。

使用节制的重试逻辑方案

当 端口耗尽或应用程序故障发生时,无衰减或回退逻辑的积极重试或暴力重试会使耗尽状况再次发生或一直持续。如果重试过于频繁,则连接可能没有足够的时间关闭和释放 SNAT 端口以供重复使用。 使用节制的重试逻辑,可以降低对端口的需求。

  • 延时重试: 系统可能会在失败后等待一段时间,之后再尝试执行相同的操作。这样做的目的是给予系统或目标资源一些恢复时间。

  • 退避算法: 采用退避算法(如指数退避)来决定两次重试尝试之间的等待时间。例如,每次尝试失败后,系统会将等待时间翻倍,以减少对系统的冲击和避免潜在的连续失败。

  • 限制重试次数: 为了避免无限重试,可能会设置一个最大重试次数的限制。一旦达到这个限制,系统将放弃重试,并可能采取其他处理措施,如发送警告或切换到备份方案。

  • 智能判断: 重试逻辑可能还会包含对当前状态和环境的评估,只有在条件看起来有可能改善时才进行重试。

  • 随机化和分散: 在分布式系统中,如果多个实例几乎同时遇到问题并进行重试,可能会造成资源争用或"flood"效应。因此,引入随机化因素使得重试尝试更加分散可以减少这种风险。

前言


公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架(每周至少会推荐两个优秀的项目和框架当然节假日除外),公众号推文中有项目和框架的介绍、功能特点、使用方式以及部分功能截图等(打不开或者打开GitHub很慢的同学可以优先查看公众号推文,文末一定会附带项目和框架源码地址)。注意:排名不分先后,都是十分优秀的开源项目和框架,每周定期更新分享(欢迎关注公众号:
追逐时光者
,第一时间获取每周精选分享资讯