2019년과 이후 JavaScript의 동향 - WebAssembly

WebAssembly는 C와 C++ 같은 프로그래밍 언어를 컴파일해 어느 브라우저에서나 빠르게 실행되는 바이너리 형식(low-level language)으로 바꾸는 기술입니다. 별도의 플러그인을 사용하지 않고 브라우저에서 네이티브 언어 수준의 성능을 보여 줄 수 있는 기술이 WebAssembly의 목표입니다.

주요 브라우저와 Node.js가 WebAssembly를 기본으로 지원하면서 아직 더디지만 WebAssembly를 활용하는 사례가 늘고 있습니다. 이 글에서는 다양한 WebAssembly 활용 사례와 성능 테스트 사례를 살펴보고, 표준 명세에서 논의 중인 제안을 몇 가지 알아보겠습니다. 마지막으로 WebAssembly를 브라우저 밖에서 활용하려는 표준인 WASI(WebAssembly System Interface)의 움직임을 살펴보겠습니다.

이 글의 내용은 2019년 6월을 기준으로 작성되었습니다. 글을 읽는 시점에 따라 글의 내용과 사실이 다를 수 있습니다.

다양한 WebAssembly 활용 사례

2017년에 주요 브라우저가 WebAssembly를 지원하기 시작한 이후로 WebAssembly를 지원하는 영역이 서서히 넓어지고 있다. 몇몇 사례를 통해 WebAssembly가 어떻게 활용되는지 살펴보겠다.

Microsoft의 Blazor

Microsoft가 2018년 2월에 발표한 Blazor는 C#과 Razor(ASP.NET에서 사용하는 뷰 엔진), HTML을 사용해 웹 UI를 만들 수 있는 실험적 .NET 웹 프레임워크이다. Blazor로 만든 앱은 WebAssembly를 통해 브라우저에서 실행된다. Blazor에 관한 더 자세한 내용은 "Blazor 소개" 문서를 참고한다.

그림 1

그림 1 브라우저에서 실행되는 Blazor 앱의 구조(원본 출처: Blazor 소개)

Go 언어

Go 언어도 WebAssembly를 지원하는 작업을 진행하고 있다. Go 1.11이 실험적으로 WebAssembly를 지원하기 시작했다. 이후 릴리스에서 지속적으로 개선 사항을 포함할 것이라고 밝히고 있다.

AssemblyScript

AssemblyScript는 TypeScript의 하위 언어(subset)로, 엄격한 타입(strictly typed) 언어이다. AssemblyScript 코드를 컴파일러인 Binaryen을 사용해 WebAssembly로 컴파일한다.

그림 2

그림 2 AssemblyScript 로고

AutoCAD의 웹 앱으로 전환

AutoCAD는 소프트웨어를 브라우저에서도 사용할 수 있게 하려고 Flash를 사용하기도 했고, HTML5와 JavaScript의 조합을 사용하기도 했다. 하지만 기능에 제약이 있고 코드를 다시 작성해야 하는 등의 문제가 있었다. WebAssembly를 사용하면서는 35년 전에 작성된 C++ 코드를 재작성하지 않고도 사용할 수 있어서 AutoCAD를 웹 앱으로 성공적으로 전환했다. WebAssembly를 사용한 AutoCAD의 웹 앱 전환에 관한 더 자세한 내용은 Google I/O 2018의 "Build the future of the web with WebAssembly and more" 세션 발표 영상을 참고한다.

그림 3

그림 3 AutoCAD 웹 앱의 구조(원본 출처: "Build the future of the web with WebAssembly and more (Google I/O '18)" 세션 발표 영상)

그 외의 활용 사례

그 외에 다음 사례도 참고하기 바란다.

  • WebAssembly Studio: 온라인 IDE(integrated development environment)를 사용해 C와 Rust, AssemblyScript 등으로 WebAssembly 코드를 작성해 볼 수 있는 플레이그라운드 사이트이다.
  • Extending the browser with WebAssemblyAlliance for Open Media의 AV1 비디오 코덱의 소스 코드를 감싸는 래퍼(wrapper)를 빌드해 브라우저에서 코덱을 실행할 수 있게 하는 과정을 소개하는 글이다.
  • Emscripten and npm: 일반적인 웹 애플리케이션 프로젝트에 WebAssembly 모듈을 통합하기 위해 준비해야 하는 설정을 설명하는 글이다.

WebAssembly 성능 테스트 사례

WebAssembly는 어셈블리 언어처럼 바이너리로 컴파일되기 때문에 네이티브 언어에 가까운 성능을 나타낼 수 있다고 알려져 있다. 실제로 그런 성능을 보여 줄까?

WebAssembly의 성능을 엿볼 수 있는 테스트 사례를 살펴보면 아직까지는 네이티브 언어와 동일한 수준의 성능을 보여 주지는 못한다. 그러나 발전하고 있는 기술이기 때문에 앞으로 보다 많은 개선이 이루어지면 성능 문제도 해결될 수 있을 것이라 생각한다.

Firefox에서 JavaScript와 WebAssembly 사이의 함수 호출 시간을 줄이기 위한 노력을 "Calls between JavaScript and WebAssembly are finally fast" 글에서 확인할 수 있다.

WebAssembly와 네이티브 코드 성능 분석

매사추세츠 애머스트 대학교(University of Massachusetts Amherst)에서 진행한 테스트에서는 WebAssembly로 컴파일된 애플리케이션이 네이티브 언어로 컴파일된 애플리케이션보다 평균적으로 Firefox에서는 45%, Chrome에서는 55% 더 느리게 실행됐다. 최대 2.08배(Firefox)와 2.5배(Chrome) 더 느린 성능을 나타내기도 했다고 한다. 성능 저하 이유는 일부 영역의 최적화 부족과 코드 생성 이슈, WebAssembly 플랫폼 자체의 문제 등이라고 보고 있다.

그림 4

그림 4 CPU 사이클에 대한 SPEC CPU 벤치마크 테스트 결과

WebAssembly와 JavaScript 폴백

문서를 PDF로 변환하는 도구인 PSPDFKit가 "A Real-World WebAssembly Benchmark"에서 공개한 벤치마크 결과도 참고할 만하다.

50만 줄의 C++ 코드를 WebAssembly로 컴파일했을 때 Firfox를 제외한 대다수의 브라우저에서 JavaScript 폴백(asm.js 빌드 버전)보다 높은 성능을 보여 주지 못했다. 일부 환경에서는 심지어 더 낮은 성능을 보였다고 한다.

그림 5

그림 5 WebAssembly와 JavaScript 폴백 벤치마크 테스트 결과

벤치마크 결과를 공개한 이후에는 브라우저 제조사와 긴말하게 협업해 이전보다 향상된 결과를 얻었다. 벤치마크 결과를 더 보려면 WebAssembly Benchmark by PSPDFKit 페이지를 참고한다.

WebAssembly와 JavaScript

Google은 Google I/O 2018에서 웹 기반 이미지 최적화 도구인 Squoosh를 발표했다. Squoosh는 C++로 작성되고 WebAssembly로 컴파일되었다. Squoosh의 이미지 회전 기능은 JavaScript 함수로 구현했고, 이미지의 각 픽셀을 반복적으로 읽어 들여 다른 위치로 복사하는 형태의 알고리즘을 적용했다.

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

이미지 회전 기능에 적용한 알고리즘을 사용하면, 예를 들어, 4094 픽셀 x 4094 픽셀 크기의 이미지를 회전할 때 1천6백만 번의 반복 작업을 수행하게 된다. 이 작업을 실행할 때 브라우저별로 성능에 차이가 났다. 대체로 2초 내외로 수행되었으나 일부 브라우저에서는 8초 정도가 걸리기도 했다.

"Replacing a hot path in your app's JavaScript with WebAssembly" 글에서는 이미지 회전 기능을 JavaScript에서 WebAssembly로 전환해 구현하기로 결정한 과정을 설명한다. 다음과 같이 여러 언어의 성능을 비교하고 최종으로 Rust로 구현한 버전을 적용했다.

그림 6

그림 6 언어별 브라우저 실행 성능 비교

Rust와 WebAssembly 사용에 관한 자세한 내용은 "Rust and WebAssembly ebook" 문서를 참고한다.

WebAssembly 표준 명세와 흥미로운 제안

WebAssembly의 표준 명세는 WebAssembly의 임베딩이 다양한 환경에서 가능하도록 명세를 2개의 계층으로 분리했다.

  • 핵심 명세(core specification): 임베딩 환경과 상관없는 WebAssembly의 언어와 문법을 정의하는 명세이다. WebAssembly 모듈의 구조, 명령어, 바이너리 표현식, 텍스트 표현식 등에 관한 정의를 포함한다.
  • 임베딩 환경 관련 명세(embedder specifications): 임베딩 환경에 따라 WebAssembly 모듈과 상호작용을 하기 위한 API를 정의하는 명세이다.
    • JavaScript Interface: WebAssembly에 접근하는 JavaScript 클래스와 객체, 메서드를 정의한 JavaScript API이다.
    • Web API: 브라우저에서 사용할 수 있게 JavaScript API를 확장한 명세이다.

WebAssembly의 표준화 절차는 ECMAScript의 표준화 절차와 유사하며, 총 6단계(Phase 0~Phase 5)를 통해 표준화가 진행된다. 현재 진행 중인 WebAssembly에 대한 모든 제안은 "WebAssembly proposals"에서 확인할 수 있다.

논의 중인 제안에서 흥미로운 제안 두 가지를 간략하게 살펴보겠다.

WebAssembly와 ESM의 통합

"WebAssembly/ES Module Integration"에서는 WebAssembly를 ESM(ECMAScript Module)처럼 import 구문으로 로딩할 수 있게 하자고 제안한다. 현재 Phase 2 단계에 있는 제안이다. WebAssembly와 ESM의 통합에 관한 더 자세한 내용은 "WebAssembly ES module integration" 동영상을 참고한다.

// current WebAssembly module instantiation
let req = fetch("./myModule.wasm");  
let imports = {aModule: anImport};

WebAssembly  
  .instantiateStreaming(req, imports)
  .then(obj => obj.instance.exports.foo());

// as ESM
import {foo} from "./myModule.wasm";  
foo();  

스레드

브라우저는 2012년부터 웹 워커를 통해 병렬성(parallelism)을 지원한다. 웹 워커 스레드는 가변 데이터(mutable)를 서로 공유하지 않으며(SharedArrayBuffer 객체로 공유할 수도 있다), 웹 워커 스레드 사이의 통신은 메시지 기반으로 이루어진다. Chrome은 스레드별로 새로운 V8 엔진을 할당한다(isolation). Chrome에서 스레드는 컴파일된 코드 또는 JavaScript 객체 등을 서로 공유하지 않는다.

WebAssembly 스레드 명세는 SharedArrayBuffer 객체를 사용해 스레드가 메모리를 서로 공유할 수 있게 한다. 그리고 각 스레드는 웹 워커를 통해 실행되게 한다. 스레드를 사용하는 애플리케이션은 공유된 메모리의 접근을 관리해야 한다. 이 명세를 따르면 기존의 pthreads(POSIX Threads, UNIX에서 스레드를 관리하는 표준 API)를 사용해 작성된 많은 C/C++ 코드와 라이브러리가 WebAssembly로 컴파일되어 스레드 모드로 실행될 수 있게 된다.

Chrome 70 이후에 나온 버전에서는 chrome://flags/#enable-webassembly-threads 플래그를 설정해 WebAssembly 스레드를 사용할 수 있다. Chrome에서 WebAssembly 스레드 사용에 관해서는 "WebAssembly Threads ready to try in Chrome 70" 글을 참고한다.

새로운 WebAssembly 표준을 위한 움직임, WASI

그림 7

그림 7 WASI 로고

Mozilla는 브라우저 밖에서 WebAssembly를 실행할 수 있게 하자는 새로운 제안인 'WASI(WebAssembly system interface)'를 2019년 3월 27일에 발표했다. 많은 개발자가 WebAssembly를 브라우저 외의 영역에서 사용하기를 원하면서 새로운 제안이 필요해졌다고 설명한다("Standardizing WASI: A system interface to run WebAssembly outside the web" 참고).

WebAssembly는 물리적(physical) 장치가 아닌 개념적(conceptual) 장치를 대상으로 하는 어셈블리 언어이기 때문에 다양한 운영체제와 환경에서 실행될 수 있는 조건을 이미 갖추고 있다. 브라우저 외의 영역에서 WebAssembly를 실행하게 하려면 단일한 특정 운영체제가 아니라 개념적 운영체제를 대상으로 하는 시스템 인터페이스가 필요하다. 개념적 운영체제를 대상으로 하는 시스템 인터페이스는 통일된 시스템 인터페이스(WASI)를 사용하기 때문에 서로 다른 운영체제의 시스템 인터페이스를 알지 못하더라도 WebAssembly가 서로 다른 운영체제와 대화할 수 있다.

시스템 인터페이스
시스템 인터페이스는 운영체제와 환경에 상관없이 사용할 수 있게 제공되는 공통의 인터페이스이다.
시스템 자원(파일, 메모리, 네트워크 연결 등)은 운영체제의 안정성 및 보안과 밀접히 연계되어 있기 때문에 매우 중요하다. 만약 애플리케이션이 시스템 자원에 직접 접근하는 데 아무런 제약이 없다면 상황에 따라 의도하거나 의도하지 않게 다른 애플리케이션이 사용하고 있는 자원을 엉망으로 만들 수 있다. 이로 인해 시스템 크래시가 발생할 수도 있고 민감한 데이터가 유출될 수도 있다.
이러한 문제점을 방지하기 위해 애플리케이션 또는 사용자가 접근할 수 있는 자원을 관리할 필요가 있다. 애플리케이션과 시스템 자원 사이에 위치하는 '커널(kernel)'을 통해 시스템 자원으로 접근을 관리한다. 커널에 대한 작업 요청은 시스템 호출(system call)을 통해 처리된다. 시스템 호출은 애플리케이션이 시스템 자원을 사용하기 위한 커널로 '요청'을 보내는 것을 의미한다. 이때 커널은 애플리케이션과 사용자를 파악해 권한 부여 등을 처리한다.
운영체제마다 시스템 호출을 다르게 해야 한다면 애플리케이션은 운영체제마다 다른 시스템 호출 처리 코드를 포함해야 할 것이다. 일반적으로 대다수의 프로그래밍 언어는 시스템 자원 접근을 위한 기본 라이브러리(standard library)와 컴파일 대상 운영체제에 맞는 시스템 호출 구현체를 제공한다. 이들 구현체는 해당 운영체제의 시스템 API를 사용하도록 구현되어 있다.
시스템 인터페이스는 이처럼 각각 다른 환경에 상관없이 사용될 수 있도록 제공되는 공통의 인터페이스를 의미한다.

WebAssembly는 다음과 같은 2개의 원칙을 가지고 있다. WASI 또한 이 원칙을 유지하며 디자인된다.

  • 이식성(portability): 동일한 코드를 다양한 플랫폼에서 실행할 수 있다.
  • 보안(security): WebAssembly는 샌드박스에서 실행되기 때문에 운영체제와 직접 대화할 수 없다. 호스트(브라우저 또는 WebAssembly 런타임)가 샌드박스 내의 코드가 사용할 수 있는 함수를 설정한다. 이런 방식으로 프로그램마다 제약을 다르게 설정할 수 있다.

다음은 Rust로 작성한 간단한 WASI 예제이다.

$ cargo new --bin hello-world

# marin.rs
fn main() {  
    println!("Hello, World!");
}

$ cargo build --target wasm32-unknown-wasi
$ wasmtime target/wasm32-unknown-wasi/debug/hello-world.wasm

Hello, World!  

현재 4개의 WASI 구현체가 있다.

WASI는 Java의 캐치프레이즈였던 "Write once, run anywhere"(한 번 작성한 코드를 어디에서나 실행한다)를 떠올리게 한다. 아직 시작 단계이고 성숙하려면 많은 시간이 필요해 보이지만 잘 발전한다면 미래에 커다란 영향력을 가질 수도 있을 것이다.

"Webassembly beyond the web" 영상에서는 WASI에 관한 더 자세한 소개를 볼 수 있다.

마치며

WebAssembly의 다양한 활용 사례와 주요한 제안을 살펴봤다. 브라우저 밖에서 WebAssembly를 실행할 수 있게 하자는 제안인 WASI도 살펴봤다.

JavaScript는 언어적 측면에서 꾸준히 변화하고 있다. 프런트엔드를 위한 언어의 또 다른 축인 WebAssembly의 발전은 JavaScript와는 다른 가능성을 가지고 앞을 열어나갈 것으로 보인다

다음 글에서는 대표적인 프런트엔드 라이브러리와 프레임워크의 동향을 다루겠다.

 

[출처] https://d2.naver.com/helloworld/8786166

 

 

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
71 무작정 배우는 C언어 머드(MUD)게임 만들기 Part4 게임스랩 file 졸리운_곰 2020.10.17 563
70 무작정 배우는 C언어 머드(MUD)게임 만들기 Part3 게임스랩 file 졸리운_곰 2020.10.17 1020
69 무작정 배우는 C언어 머드(MUD)게임 만들기 Part2 게임스랩 file 졸리운_곰 2020.10.17 1236
68 무작정 배우는 C언어 머드(MUD)게임만들기 Part1 게임스랩 file 졸리운_곰 2020.10.17 5646
67 [python] [ pyGame] 컴퓨터그래픽스 : 그래픽 프리미티브 그리기 file 졸리운_곰 2020.08.09 397
66 How to Make a Mini Minecraft Game file 졸리운_곰 2020.07.20 344
65 Learn to Develop Alphabet Learning Mobile Game for Kids using Mobile Blazor Bindings file 졸리운_곰 2020.07.04 260
64 Coding your own blockchain with Unity3D file 졸리운_곰 2020.01.02 365
63 Cheat Engine source 게임 해킹 치트엔진 소스 file 졸리운_곰 2019.12.28 461
» 2019년과 이후 JavaScript의 동향 - WebAssembly file 졸리운_곰 2019.12.19 290
61 Compiling a New C/C++ Module to WebAssembly 졸리운_곰 2019.12.19 363
60 [개발바보]WebAssembly, 브라우저에 올리는 네이티브 코드 file 졸리운_곰 2019.12.19 278
59 Rust 코드를 웹 (어셈블리)로 전환 : Compiling from Rust to WebAssembly 졸리운_곰 2019.12.19 364
58 WebAssembly 101: a developer's first steps file 졸리운_곰 2019.12.19 455
57 짱! 웹 어셈블리 문서 링크 Awesome Wasm file 졸리운_곰 2019.12.19 535
56 웹어셈블리의 컨셉, 어셈블리가 뭔가요? file 졸리운_곰 2019.12.18 583
55 파이썬과 웹 어셈블리 Python and WebAssembly file 졸리운_곰 2019.12.18 1663
54 [Web Assembly] Exploring Blazor with Visual Studio 2019 file 졸리운_곰 2019.12.18 6597
53 [Unity] ML-Agent 설치 및 실행 file 졸리운_곰 2019.08.15 621
52 유니티 머신러닝 에이전트 소개 file 졸리운_곰 2019.08.15 694
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED