{"id":317393,"date":"2021-02-03T09:00:36","date_gmt":"2021-02-03T09:00:36","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=317393"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=317393","title":{"rendered":"\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c AssemblyScript \u0432 Go"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\">\n<p>\u041f\u043e\u043a\u0430 \u043e\u0434\u043d\u0438 \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u044e\u0442 <a href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/539100\/\">\u0447\u0442\u043e \u043d\u0435 \u0442\u0430\u043a \u0441 WebAssembly<\/a>, \u044f \u0434\u0443\u043c\u0430\u044e \u043a\u0430\u043a \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u043d\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 <a href=\"https:\/\/www.envoyproxy.io\/docs\/envoy\/v1.17.0\/configuration\/http\/http_filters\/wasm_filter#config-http-filters-wasm\">wasm \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432<\/a> \u0434\u043b\u044f Envoy. AssemblyScript \u0431\u044b\u043b \u0432\u0437\u044f\u0442 \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u044d\u0442\u043e \u043d\u0435 C++ \u0438 \u043d\u0435 Rust, \u0442.\u0435. \u043e\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044f \u0431\u043e\u043b\u0435\u0435 \u043d\u0438\u0437\u043a\u0438\u0439 \u043f\u043e\u0440\u043e\u0433 \u0432\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f. \u041f\u043e\u0434 \u043a\u0430\u0442\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0434\u0438\u043a\u043e \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u043d\u044b\u0439 \u043a\u043e\u0434 \u0438 \u043f\u0430\u0440\u0443 \u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u043e\u0432. \u041a\u0430\u0440\u0442\u0438\u043d\u043a\u0430 \u0432\u0437\u044f\u0442\u0430 \u0438\u0437 \u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u0430.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/cq\/ev\/j4\/cqevj4gihdqjonm_k6ohrc5bgei.png\"><\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<h2 id=\"rantaymy-dostupnye-dlya-go\">\u0420\u0430\u043d\u0442\u0430\u0439\u043c\u044b \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0434\u043b\u044f Go<\/h2>\n<p>  <\/p>\n<p>\u0411\u043e\u043b\u0435\u0435 \u043c\u0435\u043d\u0435\u0435 \u0436\u0438\u0432\u044b\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u044b \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u043c\u0435\u044e\u0442 \u0431\u0438\u043d\u0434\u0438\u043d\u0433\u0438, \u0434\u043b\u044f Go:<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/wasmerio\/wasmer-go\">wasmer-go<\/a>;<\/li>\n<li><a href=\"https:\/\/pkg.go.dev\/github.com\/bytecodealliance\/wasmtime-go\">wasmtime-go<\/a>;<\/li>\n<li><a href=\"https:\/\/github.com\/matiasinsaurralde\/go-wasm3\">go-wasm3<\/a>.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c <a href=\"https:\/\/github.com\/perlin-network\/life\">life<\/a>, \u043d\u043e \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u0432\u0448\u0438\u0441\u044c \u0441 \u0434\u0432\u0443\u043c\u044f \u0431\u0430\u0433\u0430\u043c\u0438 \u0432 life \u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c \u043a\u043e\u043c\u043c\u0438\u0442 \u043e\u0442 2019 \u043f\u043e\u043d\u044f\u043b, \u0447\u0442\u043e \u043f\u0440\u043e\u0435\u043a\u0442 \u043c\u0435\u0440\u0442\u0432. \u041f\u043e\u0432\u0435\u043b\u0441\u044f \u0438\u0437-\u0437\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043b\u0438\u043c\u0438\u0442 \u043d\u0430 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439(<a href=\"https:\/\/godoc.org\/github.com\/perlin-network\/life\/exec#VirtualMachine.RunWithGasLimit\">gas metering<\/a>). \u0412 wasmer <a href=\"https:\/\/docs.wasmer.io\/ecosystem\/wasmer\/wasmer-features\">metering<\/a>, \u043d\u043e \u0432 wasmer-go \u043f\u043e\u043a\u0430 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e.<\/p>\n<p>  <\/p>\n<h2 id=\"hello-world\">Hello World!<\/h2>\n<p>  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u044b, \u0442\u043e \u0442\u0438\u043f\u0438\u0447\u043d\u044b\u0439 hello world \u044d\u0442\u043e:<\/p>\n<p>  <\/p>\n<pre><code class=\"rust\">extern {     fn sum(x: i32, y: i32) -&gt; i32; }  #[no_mangle] pub extern fn add1(x: i32, y: i32) -&gt; i32 {     unsafe { sum(x, y) + 1 } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0427\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c, \u0441\u0442\u0440\u043e\u043a \u0432 MVP \u043d\u0435 \u0437\u0430\u0432\u0435\u0437\u043b\u0438. \u041d\u0430\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0438\u0441\u043b\u043e\u0432\u044b\u0435 \u0442\u0438\u043f\u044b <a href=\"https:\/\/webassembly.github.io\/spec\/core\/text\/types.html\">i32, i64, f32, f64<\/a>. \u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0432\u043e \u0447\u0442\u043e \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u0441\u044f \u044d\u0442\u043e\u0442 \u043a\u043e\u0434:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import {console} from &quot;..\/..\/assemblyscript\/go&quot;;  export function hello(): void{     console.log(&quot;Hello World!&quot;) }  \/\/ go.ts export declare namespace console {     export function log(s: string): void }<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"plaintext\">(module  (type $none_=&gt;_none (func))  (type $i32_=&gt;_none (func (param i32)))  (import &quot;go&quot; &quot;console.log&quot; (func $..\/..\/assemblyscript\/go\/console.log (param i32)))  (memory $0 64)  (data (i32.const 4147212) &quot;,\\00\\00\\00\\01\\00\\00\\00\\00\\00\\00\\00\\01\\00\\00\\00\\18\\00\\00\\00H\\00e\\00l\\00l\\00o\\00 \\00W\\00o\\00r\\00l\\00d\\00!&quot;)  (export &quot;memory&quot; (memory $0))  (export &quot;hello&quot; (func $hello\/hello))  (func $hello\/hello   i32.const 4147232   call $..\/..\/assemblyscript\/go\/console.log  ) )<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0438\u043f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 <code>i32<\/code> \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u043d\u0430\u043c, \u0447\u0442\u043e \u044d\u0442\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u0432 \u043b\u0438\u043d\u0435\u0439\u043d\u043e\u0439 \u043f\u0430\u043c\u044f\u0442\u0438. \u0427\u0442\u043e \u0431\u044b \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443, \u043d\u0443\u0436\u043d\u043e \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u0432 \u0440\u0430\u0437\u0434\u0435\u043b <a href=\"https:\/\/www.assemblyscript.org\/memory.html#internals\">\u043f\u0430\u043c\u044f\u0442\u0438<\/a>:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">       +----------+   size        |   u16    +&lt;----------+        +----------+        |   u16    |   ptr  +----------+ +-----&gt;+    H     |        +----------+        |    e     |        +----------+        |    l     |        +----------+<\/code><\/pre>\n<p>  <\/p>\n<p>\u0423\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u0441\u0441\u044b\u043b\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0441\u0438\u043c\u0432\u043e\u043b \u0441\u0442\u0440\u043e\u043a\u0438, \u043f\u043e \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u044e -4 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0434\u043b\u0438\u043d\u0430. \u0412 Go<br \/>  \u043d\u0430\u043c \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c:<\/p>\n<p>  <\/p>\n<pre><code class=\"go\">var (     LE = binary.LittleEndian )  const (     SizeOffset = -4 )  func ToString(memory *wasmer.Memory, ptr int64) string {     data := memory.Data()     len := LE.Uint32(data[ptr+SizeOffset:]) &gt;&gt; 1     buf := bytes.NewReader(data[ptr:])      tmp := make([]uint16, 0, len)     for i := uint32(0); i &lt; len; i++ {         var j uint16         _ = binary.Read(buf, LE, &amp;j)         tmp = append(tmp, j)     }     return string(utf16.Decode(tmp)) }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443:<\/p>\n<p>  <\/p>\n<pre><code class=\"go\">package main  import (     &quot;flag&quot;     &quot;fmt&quot;     &quot;io\/ioutil&quot;     &quot;time&quot;     helpers &quot;wasmer-go-assemblyscript&quot;      &quot;github.com\/wasmerio\/wasmer-go\/wasmer&quot; )  var callCount int  func init() {     flag.IntVar(&amp;callCount, &quot;call&quot;, 1, &quot;number of calls&quot;)     flag.Parse() }  func main() {     var globalInstane *wasmer.Instance     wasmBytes, err := ioutil.ReadFile(&quot;examples\/wasm\/optimized.wasm&quot;)     if err != nil {         panic(err)     }      engine := wasmer.NewEngine()     store := wasmer.NewStore(engine)      module, err := wasmer.NewModule(store, wasmBytes)     if err != nil {         panic(fmt.Sprintln(&quot;failed to compile module:&quot;, err))     }      log := wasmer.NewFunction(store,         wasmer.NewFunctionType(wasmer.NewValueTypes(wasmer.I32), wasmer.NewValueTypes()),         func(args []wasmer.Value) ([]wasmer.Value, error) {             memory, err := globalInstane.Exports.GetMemory(&quot;memory&quot;)             if err != nil {                 panic(fmt.Sprintln(&quot;failed get memory:&quot;, err))             }             return helpers.Log(memory, args)         },     )      importObject := wasmer.NewImportObject()     importObject.Register(&quot;go&quot;,         map[string]wasmer.IntoExtern{             &quot;console.log&quot;: log,         })      fmt.Println(&quot;instantiating module...&quot;)     instance, err := wasmer.NewInstance(module, importObject)     if err != nil {         panic(fmt.Sprintln(&quot;failed to instantiate the module:&quot;, err))     }      globalInstane = instance     hello, err := instance.Exports.GetRawFunction(&quot;hello&quot;)     if err != nil {         panic(fmt.Sprintln(&quot;failed to get raw function:&quot;, err))     }      fmt.Println(&quot;Calling `hello` function...&quot;)     for i := 0; i &lt; callCount; i++ {         ts := time.Now()         _, err = hello.Call()         fmt.Println(&quot;call duration&quot;, time.Since(ts))         if err != nil {             panic(fmt.Sprintln(&quot;Failed to call the `hello` function:&quot;, err))         }     } } \/\/... func Log(memory *wasmer.Memory, args []wasmer.Value) ([]wasmer.Value, error) {     ptr := int64(args[0].I32())     print(ToString(memory, ptr))     return nil, nil }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418\u0437 \u043d\u0435\u043f\u043e\u043d\u044f\u0442\u043d\u044b\u0445 \u043c\u043e\u043c\u0435\u043d\u0442\u043e\u0432 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043b\u0438\u0448\u044c:<\/p>\n<p>  <\/p>\n<pre><code class=\"go\">    log := wasmer.NewFunction(store,         wasmer.NewFunctionType(wasmer.NewValueTypes(wasmer.I32), wasmer.NewValueTypes())<\/code><\/pre>\n<p>  <\/p>\n<p>\u041c\u044b \u0434\u0435\u043a\u043b\u0430\u0440\u0438\u0440\u0443\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0441 \u043e\u0434\u043d\u0438\u043c \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442. \u0417\u0430\u043f\u0443\u0441\u043a:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">$ hello -call 5 instantiating module... Calling `hello` function... Hello World!call duration 20.721\u00b5s Hello World!call duration 5.51\u00b5s Hello World!call duration 4.9\u00b5s Hello World!call duration 4.95\u00b5s Hello World!call duration 4.77\u00b5s<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u0432\u044b\u0437\u043e\u0432 \u043e\u0447\u0435\u043d\u044c \u0434\u043e\u0440\u043e\u0433\u043e\u0439, \u0432\u0441\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043d\u0435\u043c\u043d\u043e\u0433\u043e, \u043d\u043e \u0434\u0435\u0448\u0435\u0432\u043b\u0435. \u041f\u043e\u0447\u0435\u043c\u0443 \u0442\u0430\u043a \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442, \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0443 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 <a href=\"https:\/\/github.com\/WAVM\/WAVM\/issues\/300#issue-788667045\">WAVM<\/a>.<\/p>\n<p>  <\/p>\n<h2 id=\"peredacha-go-strok-v-as\">\u041f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 Go \u0441\u0442\u0440\u043e\u043a \u0432 AS<\/h2>\n<p>  <\/p>\n<p>\u041e\u0434\u043d\u0438\u0445 \u0447\u0438\u0441\u043b\u043e\u0432\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e. \u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0438. \u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 <a href=\"https:\/\/www.assemblyscript.org\/runtime.html\">\u0440\u0430\u043d\u0442\u0430\u0439\u043c\u0430<\/a> AS.<\/p>\n<p>  <\/p>\n<div class=\"scrollable-table\">\n<table>\n<thead>\n<tr>\n<th>Variant<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>full<\/td>\n<td>A proper memory manager and reference-counting based garbage collector, with runtime interfaces being exported to the host for being able to create managed objects externally.<\/td>\n<\/tr>\n<tr>\n<td>half<\/td>\n<td>The same as <em>full<\/em> but without any exports, i.e. where creating objects externally is not required. This allows the optimizer to eliminate parts of the runtime that are not needed.<\/td>\n<\/tr>\n<tr>\n<td>stub<\/td>\n<td>A minimalist arena memory manager without any means of freeing up memory again, but the same external interface as <em>full<\/em>. Useful for very short-lived programs or programs with hardly any memory footprint, while keeping the option to switch to <em>full<\/em> without any further changes. No garbage collection.<\/td>\n<\/tr>\n<tr>\n<td>none<\/td>\n<td>The same as <em>stub<\/em> but without any exports, for the same reasons as explained in <em>half<\/em>. Essentially evaporates entirely after optimizations.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>  <\/p>\n<p>\u041d\u0430\u043c \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b <em>__new<\/em>, <em>__renew<\/em>, <em>__release<\/em> \u0438 \u0442.\u0434. \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0430\u043a:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/https:\/\/github.com\/AssemblyScript\/assemblyscript\/blob\/master\/lib\/loader\/index.js#L122   function __newString(str) {     if (str == null) return 0;     const length = str.length;     const ptr = __new(length &lt;&lt; 1, STRING_ID);     const U16 = new Uint16Array(memory.buffer);     for (var i = 0, p = ptr &gt;&gt;&gt; 1; i &lt; length; ++i) U16[p + i] = str.charCodeAt(i);     return ptr;   }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041c\u044b \u043f\u043e\u0439\u0434\u0435\u043c \u0434\u0440\u0443\u0433\u0438\u043c \u043f\u0443\u0442\u0435\u043c, \u0431\u0443\u0434\u0438\u043c \u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u044f\u043c\u043e \u0432 \u043f\u0430\u043c\u044f\u0442\u044c. AS \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438<br \/>  \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u0440\u0435\u0437\u0435\u0440\u0432\u0438\u0440\u043e\u0432\u0430\u0442\u044c <em>N<\/em> \u043f\u0435\u0440\u0432\u044b\u0445 \u0431\u0430\u0439\u0442, \u0443\u043a\u0430\u0437\u0430\u0432 <code>memoryBase<\/code> \u043f\u0440\u0438 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438. \u041d\u0435 \u0441\u0442\u0430\u043b \u0437\u0430\u043c\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0445\u0435\u043b\u043f\u0435\u0440:<\/p>\n<p>  <\/p>\n<pre><code class=\"go\">func (s *SharedMemory) WriteString(str string) (ptr int64, err error) {     size := len(str) * 2     need := int(s.offset) + size     if need &gt; s.size {         return 0, fmt.Errorf(&quot;need %d, available %d, all %d :%w&quot;,             need,             int64(s.size)-s.offset,             s.size,             ErrNotEnoughMemory)     }      data := utf16.Encode([]rune(str))     pair := make([]byte, 2)     ptr = s.offset&lt;&lt;32 | int64(size)     for _, rune := range data {         LE.PutUint16(pair, rune)         copy(s.mem[s.offset:], pair)         s.offset += 2     }      return }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">+-------------+-------------+ |             |             | |    32bit    |    32bit    | |             |             | +-------------+-------------+      offset        size<\/code><\/pre>\n<p>  <\/p>\n<p>\u0420\u0430\u0441\u043f\u0430\u043a\u043e\u0432\u043a\u0430 \u0432 AS \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">export namespace Go {     export function toString(ptr: i64): string {         let len = ptr &amp; 0xFFFFFFFF         ptr = ptr &gt;&gt;&gt; 32         return String.UTF16.decodeUnsafe(&lt;usize&gt;ptr, &lt;usize&gt;len)     } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418\u0442\u043e\u0433\u043e:<\/p>\n<p>  <\/p>\n<pre><code class=\"go\">    handler, err := instance.Exports.GetRawFunction(&quot;say&quot;)     if err != nil {         panic(fmt.Sprintln(&quot;failed to get raw function:&quot;, err))     }      say := handler.Native()      fmt.Println(&quot;Calling `say` function...&quot;)     for i := 0; i &lt; callCount; i++ {         ts := time.Now()         shm.Reset()         ptr, _ := shm.WriteString(fmt.Sprintf(&quot;%d: Hello World!&quot;, i))         _, err = say(ptr)         fmt.Println(&quot;call duration&quot;, time.Since(ts))         if err != nil {             panic(fmt.Sprintln(&quot;Failed to call the `say` function:&quot;, err))         }     }<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"javascript\">export function say(ptr: i64): void{     console.log(Go.toString(ptr)) }<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"plaintext\">$ string_args -call 5 Compiling module... instantiating module... Calling `say` function... 0: Hello World!call duration 24.94\u00b5s 1: Hello World!call duration 6.18\u00b5s 2: Hello World!call duration 5.341\u00b5s 3: Hello World!call duration 5.11\u00b5s 4: Hello World!call duration 4.86\u00b5s<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"stoimost-vyzova\">\u0421\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u0432\u044b\u0437\u043e\u0432\u0430<\/h2>\n<p>  <\/p>\n<p>\u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043e\u0446\u0435\u043d\u0438\u0442\u044c \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u0432\u044b\u0437\u043e\u0432\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u0414\u043b\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u0432\u0437\u044f\u043b:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">export function empty(): void { }  let cnt = 0  export function increment(): void{     cnt++ }<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"go\">\/\/static void emptyFunction() { \/\/ \/\/} import &quot;C&quot;  func EmptyCFunction() {     C.emptyFunction() }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c 1 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u043a\u0443\u043d\u0434\u0443, \u0447\u0442\u043e \u043d\u0430 \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0431\u043e\u043b\u044c\u0448\u0435 \u0447\u0435\u043c \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u0432\u044b\u0437\u043e\u0432 CGO:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">BenchmarkIncr-12                 1000000          1150 ns\/op BenchmarkEmptyFunction-12         981108          1140 ns\/op BenchmarkEmptyCFunction-12      36840853            31.8 ns\/op<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"2048-ottenkov-serogo\">2048 \u043e\u0442\u0442\u0435\u043d\u043a\u043e\u0432 \u0441\u0435\u0440\u043e\u0433\u043e<\/h2>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/cq\/ev\/j4\/cqevj4gihdqjonm_k6ohrc5bgei.png\"><\/p>\n<p>  <\/p>\n<p>\u041d\u0443\u0436\u043d\u0430 \u0431\u044b\u043b\u0430 CPU Bound \u0437\u0430\u0434\u0430\u0447\u0430, \u0447\u0442\u043e \u0431\u044b \u0432\u0440\u0435\u043c\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u043a\u0440\u044b\u0432\u0430\u043b\u0430 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u0432\u044b\u0437\u043e\u0432\u0430. \u0412\u0437\u044f\u043b \u043f\u0440\u0438\u043c\u0435\u0440 \u0441 <a href=\"https:\/\/www.assemblyscript.org\/examples\/mandelbrot.html#example\">\u0441\u0430\u0439\u0442\u0430 AS<\/a> \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043b \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f 1920&#215;1080.<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/** Number of discrete color values on the JS side. *\/ const NUM_COLORS = 2048;  \/** Updates the rectangle `width` x `height`. *\/ export function update(width: u32, height: u32, limit: u32): void {     let translateX = width  * (1.0 \/ 1.6);     let translateY = height * (1.0 \/ 2.0);     let scale      = 10.0 \/ min(3 * width, 4 * height);     let realOffset = translateX * scale;     let invLimit   = 1.0 \/ limit;      let minIterations = min(8, limit);      for (let y: u32 = 0; y &lt; height; ++y) {         let imaginary = (y - translateY) * scale;         let yOffset   = (y * width) &lt;&lt; 1;          for (let x: u32 = 0; x &lt; width; ++x) {             let real = x * scale - realOffset;              \/\/ Iterate until either the escape radius or iteration limit is exceeded             let ix = 0.0, iy = 0.0, ixSq: f64, iySq: f64;             let iteration: u32 = 0;             while ((ixSq = ix * ix) + (iySq = iy * iy) &lt;= 4.0) {                 iy = 2.0 * ix * iy + imaginary;                 ix = ixSq - iySq + real;                 if (iteration &gt;= limit) break;                 ++iteration;             }              \/\/ Do a few extra iterations for quick escapes to reduce error margin             while (iteration &lt; minIterations) {                 let ixNew = ix * ix - iy * iy + real;                 iy = 2.0 * ix * iy + imaginary;                 ix = ixNew;                 ++iteration;             }              \/\/ Iteration count is a discrete value in the range [0, limit] here, but we'd like it to be             \/\/ normalized in the range [0, 2047] so it maps to the gradient computed in JS.             \/\/ see also: http:\/\/linas.org\/art-gallery\/escape\/escape.html             let colorIndex = NUM_COLORS - 1;             let distanceSq = ix * ix + iy * iy;             if (distanceSq &gt; 1.0) {                 let fraction = Math.log2(0.5 * Math.log(distanceSq));                 colorIndex = &lt;u32&gt;((NUM_COLORS - 1) * clamp&lt;f64&gt;((iteration + 1 - fraction) * invLimit, 0.0, 1.0));             }             store&lt;u16&gt;(yOffset + (x &lt;&lt; 1), colorIndex);         }     } }  \/** Clamps a value between the given minimum and maximum. *\/ function clamp&lt;T&gt;(value: T, minValue: T, maxValue: T): T {     return min(max(value, minValue), maxValue); }<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"go\">func min(a, b uint32) uint32 {     if a &lt; b {         return a     }     return b }  func fmin(a, b float64) float64 {     if a &lt; b {         return a     }     return b }  func fmax(a, b float64) float64 {     if a &gt; b {         return a     }     return b }  func fclam(value, minValue, maxValue float64) float64 {     return fmin(fmax(value, minValue), maxValue) }  \/\/go:noinline func Naive(width, height, limit uint32, out []byte) {     translateX := float64(width) * (1.0 \/ 1.6)     translateY := float64(height) * (1.0 \/ 2.0)     scale := 10.0 \/ float64(min(3*width, 4*height))     realOffset := translateX * scale     invLimit := 1.0 \/ float64(limit)      minIterations := min(8, limit)     for y := uint32(0); y &lt; height; y++ {         imaginary := (float64(y) - translateY) * scale         yOffset := (y * width) &lt;&lt; 1          for x := uint32(0); x &lt; width; x++ {             real := float64(x)*scale - realOffset              ix := 0.0             iy := 0.0             var ixSq, iySq float64             iteration := uint32(0)             for ixSq+iySq &lt;= 4.0 {                 iy = 2.0*ix*iy + imaginary                 ix = ixSq - iySq + real                 if iteration &gt;= limit {                     break                 }                 ixSq = ix * ix                 iySq = iy * iy                 iteration++             }              for iteration &lt; minIterations {                 ixNew := ix*ix - iy*iy + real                 iy = 2.0*ix*iy + imaginary                 ix = ixNew                 iteration++             }              colorIndex := uint16(NumColors - 1)             distanceSq := ix*ix + iy*iy             if distanceSq &gt; 1.0 {                 fraction := math.Log2(0.5 * math.Log(distanceSq))                 colorIndex = uint16((NumColors - 1) * fclam((float64(iteration)+1-fraction)*invLimit, 0.0, 1.0))             }             offset := yOffset + (x &lt;&lt; 1)             out[offset] = byte(colorIndex &amp; 0xFFFF)             out[offset+1] = byte(colorIndex &gt;&gt; 8)         }     } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">BenchmarkNaive-12                  7     146213621 ns\/op           0 B\/op          0 allocs\/op BenchmarkAssembly-12               8     135236607 ns\/op         458 B\/op         16 allocs\/op<\/code><\/pre>\n<p>  <\/p>\n<p>AS \u043d\u0430 10 \u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434 \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u0447\u0435\u043c \u043d\u0430\u0438\u0432\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u043d\u0430 Go. \u041d\u043e \u0442\u0443\u0442 \u0432\u044b\u0445\u043e\u0434\u0438\u0442 &quot;\u0433\u043d\u0443\u0442\u044b\u0439&quot;, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0434\u0430\u0435\u0442 \u043d\u0430 Ryzen 3600 115 \u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434, \u0447\u0442\u043e \u043d\u0430 20 \u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434 \u043f\u0440\u0435\u0432\u043e\u0441\u0445\u043e\u0434\u0438\u0442 \u0432\u0435\u0440\u0441\u0438\u044e \u043d\u0430 AS, \u0438 \u043d\u0430 30 \u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434 \u043f\u0440\u0435\u0432\u043e\u0441\u0445\u043e\u0434\u0438\u0442 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">$ go test -compiler=gccgo -gccgoflags='-O3 -march=native' -bench=. goos: linux goarch: amd64 pkg: wasmer-go-assemblyscript\/examples\/mandelbrot BenchmarkNaive-12                  9     115202147 ns\/op BenchmarkAssembly-12               8     136263914 ns\/op<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u0442\u043e\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b WebAssembly \u0432 \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447\u0430\u0445 \u0438\u0437-\u0437\u0430 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 <a href=\"https:\/\/github.com\/WebAssembly\/simd\/\">SIMD<\/a>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0435\u0441\u0442\u044c \u0432 <a href=\"https:\/\/medium.com\/wasmer\/webassembly-and-simd-13badb9bf1a8\">wasmer<\/a>, <a href=\"https:\/\/v8.dev\/features\/simd\">v8<\/a> \u0438 \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0434\u0440\u0443\u0433\u0438\u0445 \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u0430\u0445. \u0412 \u0441\u0430\u043c\u043e\u043c AS \u0442\u043e \u0436\u0435 \u043c\u043e\u0436\u043d\u043e <a href=\"https:\/\/www.assemblyscript.org\/environment.html#low-level-webassembly-operations\">\u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f<\/a>.<\/p>\n<p>  <\/p>\n<h2 id=\"rabotaet-no-est-bagi\">\u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u043d\u043e \u0435\u0441\u0442\u044c \u0431\u0430\u0433\u0438<\/h2>\n<p>  <\/p>\n<p>\u041c\u043e\u0436\u0435\u0442 \u0431\u0430\u0433\u0430, \u0430 \u043c\u043e\u0436\u0435\u0442 by design. \u041f\u0440\u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0435 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 cancellation token, \u0432\u044b\u043b\u0435\u0437\u043b\u0430 \u043f\u0430\u043d\u0438\u043a\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"go\">    go func() {         time.Sleep(time.Millisecond * 100)         memory, err := globalInstane.Exports.GetMemory(&quot;memory&quot;)         if err != nil {             panic(err)         }         fmt.Println(&quot;canceling&quot;)         binary.LittleEndian.PutUint64(memory.Data(), 1)     }()     infinityLoop := handler.Native()     _, err = infinityLoop()<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"javascript\">function isCanceled(): boolean{     let register = load&lt;u64&gt;(0)     return register != 0 }  export function infinityLoop(): void{     let i = 0     while (!isCanceled()) {         i++         console.log(&quot;iteration:&quot; + i.toString()+&quot;\\n&quot;)     } }<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"bash\">iteration:13639 iteration:13640 iteration:13641 iteration:13642 iteration:13643 iteration:13644 panic: Host function `1` does not exist  goroutine 1 [running]: github.com\/wasmerio\/wasmer-go\/wasmer.function_trampoline(0xc0000123a0, 0x7ffca8ad78c8, 0x7ffca8ad78b0, 0x0)         \/home\/dmitry\/GolangWorkspace\/pkg\/mod\/github.com\/wasmerio\/wasmer-go@v1.0.0-beta2.0.20210113150733-ddc164edfd68\/wasmer\/function.go:96 +0x12c github.com\/wasmerio\/wasmer-go\/wasmer._cgoexpwrap_55cc7d6d4e49_function_trampoline(0xc0000123a0, 0x7ffca8ad78c8, 0x7ffca8ad78b0, 0x0)         _cgo_gotypes.go:1995 +0x74 github.com\/wasmerio\/wasmer-go\/wasmer._Cfunc_wasm_func_call(0xed1250, 0xc0000123f0, 0xc0000123e0, 0x0)         _cgo_gotypes.go:967 +0x4e github.com\/wasmerio\/wasmer-go\/wasmer.(*Function).Native.func1.5(0xc00007a2d0, 0xc0000123f0, 0xc0000123e0, 0x5d6308)         \/home\/dmitry\/GolangWorkspace\/pkg\/mod\/github.com\/wasmerio\/wasmer-go@v1.0.0-beta2.0.20210113150733-ddc164edfd68\/wasmer\/function.go:225 +0xd1 github.com\/wasmerio\/wasmer-go\/wasmer.(*Function).Native.func1(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)         \/home\/dmitry\/GolangWorkspace\/pkg\/mod\/github.com\/wasmerio\/wasmer-go@v1.0.0-beta2.0.20210113150733-ddc164edfd68\/wasmer\/function.go:225 +0x414 main.main()         \/home\/dmitry\/GolangWorkspace\/src\/wasmer-go-assemblyscript\/examples\/cancellation_token\/main.go:85 +0x6ff  Process finished with exit code 2<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412\u043e\u0442 \u0431\u044b\u043b\u0430 \u0445\u043e\u0441\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0438 \u0432\u043e\u0442 \u0435\u0451 \u043d\u0435 \u0441\u0442\u0430\u043b\u043e\u2026 \u041f\u043e \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044e \u0433\u0434\u0435-\u0442\u043e \u043f\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u043b \u0441\u0431\u043e\u0440\u0449\u0438\u043a \u043c\u0443\u0441\u043e\u0440\u0430. \u0411\u044b\u0441\u0442\u0440\u044b\u043c \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u043e\u043c \u043a\u043e\u0434\u0430 \u0431\u044b\u043b \u043d\u0430\u0439\u0434\u0435\u043d \u044d\u0442\u043e \u043c\u043e\u043c\u0435\u043d\u0442:<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/35\/d7\/nk\/35d7nknaxh-esyksijxkgxve50e.png\"><\/p>\n<p>  <\/p>\n<p>\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0442\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 GC \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0444\u0438\u043d\u0430\u043b\u0430\u0439\u0437\u0435\u0440. \u0421\u043f\u0438\u0448\u0435\u043c \u043d\u0430 \u0431\u0435\u0442\u0443 \u0432\u0435\u0440\u0441\u0438\u044e, \u0447\u0438\u043d\u0438\u0442\u044c\u0441\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c KeepAlive:<\/p>\n<p>  <\/p>\n<pre><code class=\"go\">    _, err = infinityLoop()     if err != nil {         panic(err)     }     runtime.KeepAlive(log)<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"itogi\">\u0418\u0442\u043e\u0433\u0438<\/h2>\n<p>  <\/p>\n<p>\u041a\u0430\u043a\u043e\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u043c\u0438 \u0431\u043b\u043e\u043a\u0447\u0435\u0439\u043d:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c, \u043a\u043e\u0433\u0434\u0430 \u043d\u0443\u0436\u0435\u043d \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432\u043e\u0439 \u0434\u0432\u0438\u0436\u043e\u043a;<\/li>\n<li>\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0439, \u0442.\u0435. \u043f\u043e\u0439\u0442\u0438 \u043f\u0443\u0442\u0451\u043c Envoy. \u0423\u0434\u043e\u0431\u043d\u043e \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0442\u0435\u0431\u0435 dll\/so.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0412\u0441\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043d\u0430 <a href=\"https:\/\/github.com\/RPG-18\/wasmer-go-assemblyscript\">GitHub<\/a>.<\/p>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/ozontech\/blog\/540472\/\"> https:\/\/habr.com\/ru\/company\/ozontech\/blog\/540472\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\">\n<p>\u041f\u043e\u043a\u0430 \u043e\u0434\u043d\u0438 \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u044e\u0442 <a href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/539100\/\">\u0447\u0442\u043e \u043d\u0435 \u0442\u0430\u043a \u0441 WebAssembly<\/a>, \u044f \u0434\u0443\u043c\u0430\u044e \u043a\u0430\u043a \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u043d\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 <a href=\"https:\/\/www.envoyproxy.io\/docs\/envoy\/v1.17.0\/configuration\/http\/http_filters\/wasm_filter#config-http-filters-wasm\">wasm \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432<\/a> \u0434\u043b\u044f Envoy. AssemblyScript \u0431\u044b\u043b \u0432\u0437\u044f\u0442 \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u044d\u0442\u043e \u043d\u0435 C++ \u0438 \u043d\u0435 Rust, \u0442.\u0435. \u043e\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044f \u0431\u043e\u043b\u0435\u0435 \u043d\u0438\u0437\u043a\u0438\u0439 \u043f\u043e\u0440\u043e\u0433 \u0432\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f. \u041f\u043e\u0434 \u043a\u0430\u0442\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0434\u0438\u043a\u043e \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u043d\u044b\u0439 \u043a\u043e\u0434 \u0438 \u043f\u0430\u0440\u0443 \u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u043e\u0432. \u041a\u0430\u0440\u0442\u0438\u043d\u043a\u0430 \u0432\u0437\u044f\u0442\u0430 \u0438\u0437 \u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u0430.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/cq\/ev\/j4\/cqevj4gihdqjonm_k6ohrc5bgei.png\"><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-317393","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/317393","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=317393"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/317393\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=317393"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=317393"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=317393"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}