惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
G
GRAHAM CLULEY
WordPress大学
WordPress大学
人人都是产品经理
人人都是产品经理
Apple Machine Learning Research
Apple Machine Learning Research
Jina AI
Jina AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
大猫的无限游戏
大猫的无限游戏
MyScale Blog
MyScale Blog
Forbes - Security
Forbes - Security
Hugging Face - Blog
Hugging Face - Blog
博客园 - 聂微东
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The Last Watchdog
The Last Watchdog
N
News and Events Feed by Topic
TaoSecurity Blog
TaoSecurity Blog
SecWiki News
SecWiki News
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
小众软件
小众软件
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
L
LINUX DO - 最新话题
腾讯CDC
博客园 - 三生石上(FineUI控件)
Attack and Defense Labs
Attack and Defense Labs
S
Secure Thoughts
博客园 - 叶小钗
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Webroot Blog
Webroot Blog
Google Online Security Blog
Google Online Security Blog
S
Security @ Cisco Blogs
S
Schneier on Security
罗磊的独立博客
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - Franky
Hacker News: Ask HN
Hacker News: Ask HN
T
Tenable Blog
V
V2EX
J
Java Code Geeks
AWS News Blog
AWS News Blog
博客园 - 司徒正美
V
Visual Studio Blog
T
The Exploit Database - CXSecurity.com
H
Hacker News: Front Page
Security Latest
Security Latest
月光博客
月光博客
The Hacker News
The Hacker News
T
Tor Project blog
Project Zero
Project Zero
P
Privacy & Cybersecurity Law Blog
阮一峰的网络日志
阮一峰的网络日志

博客园 - Artech

[MAF预定义的AIContextProvider-05]CompactionProvider——采用多种策略压缩对话历史 [MAF预定义的AIContextProvider-04]Mem0Provider——长期记忆基于的云端解决方案 [MAF预定义的AIContextProvider-03]ChatHistoryMemoryProvider——赋予Agent从经验中学习的能力 [MAF预定义的AIContextProvider-02]AgentSkillsProvider——将Agent Skills引入MAF [MAF预定义的AIContextProvider-01]TextSearchProvider——RAG在MAF中的实现 [MAF预定义ChatClient中间件-09]MessageInjectingChatClient-赋予工具消息注入的能力 [MAF预定义ChatClient中间件-08]OpenTelemetryChatClient-实现链路跟踪和性能监控 [MAF预定义ChatClient中间件-07]PerServiceCallChatHistoryPersistingChatClient——基于ReAct循环的一步一存档 [MAF预定义ChatClient中间件-06]利用ImageGeneratingChatClient开发专业图片生成Agent [MAF预定义ChatClient中间件-05]动态修改ChatOptions和请求消息 [MAF预定义ChatClient中间件-04]ReducingChatClient——精减对话历史又不丢失基本语义 [MAF预定义ChatClient中间件-03]CachingChatClient——利用缓存省钱省时间 [MAF预定义ChatClient中间件-02]FunctionInvokingChatClient——实现ReAct循环和人机交互的大功臣 [MAF预定义ChatClient中间件-01]LoggingChatClient——在调用LLM前后输出日志 [MAF的Agent管道详解-07]利用AIAgent中间件构建Agent管道 [MAF的Agent管道详解-06]ChatClientAgent对IChatClient和输入输出增强管道的整合 [MAF的Agent管道详解-06]ChatClientAgent对IChatClient和输入输出增强管道的整合 - Artech [MAF的Agent管道详解-05]对话历史的持久化和输入输出的增强 [MAF的Agent管道详解-04]如何让LLM按照要求的结构输出数据? [MAF的Agent管道详解-03]连接LLM的IChatClient对象 [MAF的Agent管道详解-02]IChatClient管道如何完美连接大模型? [MAF的Agent管道详解-01]塑智能体边界,从AIAgent抽象类开始 [对比学习LangChain和MAF-04]针对消息的设计 [对比学习LangChain和MAF-03]完全不同的Agent设计哲学 [对比学习LangChain和MAF-02]基本编程模式的差异(下篇) [对比学习LangChain和MAF-01]基本编程模式的差异(上篇) 这是一篇测试文章 我所理解的Python元模型 除了按值和引用,方法参数的第三种传递方式 方法的三种调用形式 可以调用Null的实例方法吗? 自定义Key类型的字典无法序列化的N种解决方案 为什么ASP.NET Core的路由处理器可以使用一个任意类型的Delegate 深入解析ASP.NET Core MVC的模块化设计[下篇] 深入解析ASP.NET Core MVC的模块化设计[上篇] ASP.NET Core MVC应用模型的构建[4]: Action的选择 ASP.NET Core MVC应用模型的构建[3]: Controller的收集 ASP.NET Core MVC应用模型的构建[2]: 定制应用模型 ASP.NET Core MVC应用模型的构建[1]: 应用的蓝图 基于HTTP2/3的流模式消息交换如何实现? 编写高效的代码,你应该了解Array、Memory、ReadOnlySequence . . . WebAssembly核心编程[4]: Memory WebAssembly核心编程[3]: Module 与 Instance WebAssembly核心编程[2]:类型系统 WebAssembly核心编程[1]:wasm模块实例化的N种方式 WebAssembly入门笔记[3]:利用Table传递引用
WebAssembly入门笔记[4]:利用Global传递全局变量
Artech · 2024-01-30 · via 博客园 - Artech

利用WebAssembly的导入导出功能可以灵活地实现宿主JavaScript程序与加载的单个wasm模块之间的交互,那么如何在宿主程序与多个wasm之间传递和共享数据呢?这就需要使用到Global这个重要的对象了。

一、数值类型全局变量
二、将JavaScript函数设置为全局变量
三、利用全局变量处理字符串

一、数值类型全局变量

Global全局变量支持多种值类型,包括数组(i32/i64和f32/f64)、向量和引用类型(externref和funcref)。下面的实例利用Global提供了全局计数的功能。在WebAssembly Text Format (WAT)文件app.wat中,我们从宿主JavaScript应用中导入了一个i32类型的可读写(mut表示可以修改)的全局变量,导入路径为“imports.counter”,我们将其命名为$counter。在用于自增的导出函数increment中,我们通过执行global.get指令读取全局变量的值,并将其加1之后,执行global.set指令对全局变量重新赋值。

(module
   (global $counter (import "imports" "counter") (mut i32))
   (func (export "increment")
       (i32.add (global.get $counter) (i32.const 1))
       (global.set $counter)
   )
)

在index.html文件中,我们在页面中添加了一个“Increment”按钮,并利用一个<span>显式计算器当前的值。JavaScript脚本通过调用WebAssembly.Global构造函数将代表全局变量的Global对象创建出来后,调用WebAssembly.instantiateStreaming加载app.wat编译生成的app.wasm模块文件,并将此Global对象包含在导入对象中。

<html>
    <head></head>
    <body>
        <span id="counter">0</span>
        <button id="btnInc">Increment</button>
        <script>
            const globalCounter = new WebAssembly.Global({ value: "i32", mutable: true }, 0);
            WebAssembly
                .instantiateStreaming(fetch("app.wasm"), {"imports":{"counter":globalCounter}})
                .then(results => {
                   document.getElementById("btnInc").onclick = ()=>{
                        results.instance.exports.increment();
                        document.getElementById("counter").innerText = globalCounter.value;
                   };
                });
        </script>
    </body>
</html>

wasm模块充成功导入后,我们注册了按钮的click事件,使之在调用导出的increment函数后,重新刷新计数器的值。如下图所示,针对“Increment”的每次点击都将计数器加1(源代码)。

image

二、将JavaScript函数设置为全局变量

除了四种数值类型,Global还支持两种引用类型externref和funcref,利用externref可以将宿主应用提供的任意JavaScript对象作为全局变量,下面的实例演示利用这种方式实现了与类似的功能。如下面的代码片段所示,新的app.wat导入了一个类型为externref的全局变量,对应着数组应用提供的一个用来对全局计数自增的Javascript函数。

(module
   (func $apply (import "imports" "apply") (param externref))
   (global $increment (import "imports" "increment") externref)
   (func $main
        (call $apply (global.get $increment))
   )
   (start $main)
)

由于JavaScript函数的引用在.wasm模块中并不能直接执行,所以我们不得不导入一个apply函数“回传”到宿主应用中执行。我们修改的应用用来统计导入的wasm模块的数量,所以我们在入口函数$main中利用apply调用了全局变量$increment引用的函数。

在index.html,我们在页面中添加了一个“Load”按钮来加载app.wat编译生成的app.wasm模块。JavaScript脚本利用counter变量表示加载的wasm模块数量,并通过调用WebAssembly.Global构造函数创建了rexternref类型的全局变量,其值为一个对counter自增的函数。

<html>
    <head></head>
    <body>
        <p>There are totally <span  id="counter" style= "color: read”>0</span> wasm modules loaded. </p>
        <button id="btnLoad">Load</button>
        <script>
            var counter = 0;
            const globalIncrement = new WebAssembly.Global({ value: "externref"}, ()=>counter++);
            var apply = func => func();
            document.getElementById("btnLoad").onclick = ()=>{
                WebAssembly
                    .instantiateStreaming(fetch("app.wasm"), {"imports":{"increment":globalIncrement,"apply": apply }})
                    .then(_=>{
                        document.getElementById("counter").innerText = counter;
                    })
                };
        </script>
    </body>
</html>

我们将这个Global对象包含到导入的对象中,并在导入成功后刷新显式的计数器,所以程序运行后将会显式当前加载的wasm模块数量(源代码)。

image

三、利用全局变量处理字符串

WebAssembly目前并没有提供针对字符串类型的直接支持,而是单纯地将其作为字节序列看到。目前字符串在宿主程序与wasm模块之间的传递只有通过Memory来实现。由于Javascript具有处理字符串的能力,wasm模块可以将字符串作为externref回传到宿主程序进行处理。在接下来演示的程序中,我们在app.wat中定义一个“字符类型(实际上是externref类型)”的全局变量,导出的greet函数通过调用导入的print函数将其输出。

(module
   (func $print (import "imports" "print") (param externref))
   (global $message (import "imports" "message") (mut externref))
   (func (export "greet")
        (call $print (global.get $message))
   )
)

在index.html中,我们在页面上放置了三个按钮,让它们在命名为“greet”的<div>中分别显示“Good Morning”、“Good Afternoon”和“Good Evening”三条问候语。具体的问候语通过函数print输出,它的参数就是代表输出文本的字符串。

<html>
    <head></head>
    <body>
        <div id="greet"></div>
        <button id="btnMorning">Morning</button>
        <button id="btnAfternoon">Afternoon</button>
        <button id="btnEvening">Evening</button>
        <script>
            var print = (msg) => {
                console.log(msg);
                document.getElementById("greet").innerText = msg;
            }
            const globalMsg = new WebAssembly.Global({ value: "externref", mutable: true }, "Good Morning!");
            console.log(globalMsg.value);
            WebAssembly
                .instantiateStreaming(fetch("app.wasm"), {"imports":{"message":globalMsg, "print":print}})
                .then(results => {
                    var greet = results.instance.exports.greet;
                    console.log(greet);
                    document.getElementById("btnMorning").onclick = ()=>{
                        globalMsg.value = "Good Morning!";
                        greet();
                    };
                    document.getElementById("btnAfternoon").onclick = ()=>{
                        globalMsg.value = "Good Afternoon!";
                        greet();
                    };
                    document.getElementById("btnEvening").onclick = ()=>{
                        globalMsg.value = "Good Evening!";
                        greet();
                    };
                });
        </script>
    </body>
</html>

我们定义了一个externref类型的Global对象来引用带输出的问候语文本,并在加载app.wasm木块使将其包含到导入对象中。三个按钮的click事件处理程序通过调用导出的greet函数输出对于的问候语,但是在调用此函数之前会对Global对象进行相应的赋值(源代码)。

image