Mercurial > hg > Papers > 2020 > koo-thesis
view Paper/chapter3.tex @ 20:0137c5074de4
update paper
author | e165727 <e165727@ie.u-ryukyu.ac.jp> |
---|---|
date | Sun, 16 Feb 2020 16:20:34 +0900 |
parents | 7d8aa97ff754 |
children | b96b3244307b |
line wrap: on
line source
\chapter{Raku によるAbyss の実装} 提案手法で述べた, 同一ホスト内で終了せずに実行を続けるサーバープロセスを立ち上げ, このサーバープロセス上で立ち上げておいたコンパイラに実行するファイル名を転送し,サーバー上でコンパイルを行う手法に沿い『Abyss Server』を実装した. \section{サーバーの構成} Abyss サーバーは クライアント側から投げられた Rakuスクリプト を実行するためのサーバーである. 図\ref{fig:AbyssExecute}は, Abyss サーバーを用いたスクリプト言語実行手順である. Abyss サーバーはユーザーが Raku を直接立ち上げるのではなく, まず 図\ref{fig:AbyssExecute} 右側の Abyss サーバーを起動し, ユーザーは Abyss サーバーにファイルパスをソケット通信で送り, Abyss サーバーがファイルを開き実行し, その実行結果をユーザーに返す. この手法を用いることで, サーバー上で事前に起動した Rakudo を再利用し, 投げられた Raku スクリプトの実行を行うため, Rakudo の起動時間を短縮できると推測できる. \begin{figure}[H] \begin{center} \includegraphics[width=80mm]{fig/abyss.pdf} \end{center} \caption{Abyssサーバーを用いたスクリプト言語実行手順} \label{fig:AbyssExecute} \end{figure} \newpage \section{Abyss Server側の実装} [\ref{Server}]はAbyss サーバーのソースコードである. Abyssサーバーは起動すると, まず自身にファイルパスを転送するためのソケットを生成し, その後ファイルパスを受け取り実行して . 出力結果をソケットに書き込む \lstinputlisting[label=Server, caption= Abyss Server側の source code ]{code/abyss.p6} \section{Abyss Client側の実装} ユーザーは Abyss Server を起動後, Client側からファイルパスをサーバーに送信し, [\ref{Client}]のようにSocketに書き込まれた実行結果を読み取る. Client側は Raku で実装されているが, Client側は Socketを生成し, filepathを送信するだけなので他の言語でも書くことが可能だ. \lstinputlisting[label=Client, caption=Abyss Client側の source code ]{code/client.p6} \section{Raku の Unix domain socket 実装} 今回, 通信するSocketにはUnix domain socket を用いた. \\ TCP socket や Async socket を用いた場合, 他者からスクリプトを送りつけられる可能性がある. そのため, 今回はUnix domain socket を用いて実装を行なった. Rakuには現在Unix domain socketの実装がないため, Unix domain socket の実装を行なった. \\ IO::Socketがroleとして定義されている \\ Raku での role は他の言語の interface に相当するものである \\ 現状 Raku にはIO::Socket::INETとIO::Socket::Asyncの実装がある \\ 前述したように, INETとAsyncはセキュリティの問題で使えない \\ IO::Socketを実装した IO::Socket::Unix を実装した \\ IO::Socket::Unixの中ではnqpの機能を使う必要がある \\ \section{Raku の EVAL} Raku ではEVAL関数[\ref{code3}]があり文字列を Raku のソースコード自身として評価できる Raku では, EVALは通常は使用できないようになっており, MONKEY-SEE-NO-EVAL という pragma を実行することで使うことができるようになる. EVALFILE はファイルパスを受け取るとファイル開き, バイト文字列に変換し読み込む, その後読み込んだバイト文字列にデコードし, ファイルパスの文字列を読み込み, ファイルの中身を EVAL と同様に解釈する. [\ref{Server}] の2行目にある MONKEY−SEE−NO−EVAL は Perl6 上で EVALFILE を使用可能にする pragma である. \lstinputlisting[label=code3, caption=evalのサンプルコード]{code/eval.p6} %通常、自分でプロセス立ち上げてPerl6を実行する際は, \section{NativeCall} Rakuでは Native Call という標準ライブラリを用いて, Cのライブラリを扱うことが可能である. \\ 指定がない場合はCの標準ライブラリが呼ばれる. [\ref{Server}]で利用したCのライブラリは以下のものである \begin{itemize} \item dup(int fd) - dup() は引数で指定したファイルディスクリプタを複製して, 未使用のファイルディスクリプタから最小番号を割り当てる. またdupはシステムコールの一種である. \item dep2(int newfd, int oldfd) - dup2() は oldfd を newfd に関連づけます. \item close(int fd) - close() は指定されたfile descreptorを閉じます. \end{itemize} \section{出力をSocketに書き込む際にdup()している理由} Raku では標準出力をSocketに書き込む API が Raku 側からは提供されていない. そのため, 通常 Code \ref{Server} のようにEVALFILEを実行した際, 出力はそのまま Server 側の標準出力に返ってしまう. この問題を解決するために, Raku の NativeCall を用いて Cのライブラリを使用した. Code \ref{Server} の26行目で dup2() を用いて 標準出力に Socket の file descreptor を割り当て, その後 EVALFILE を実行することで出力を Client側に返すことに成功した. \section{通常実行との速度比較} 今回は,提案手法での実行速度と通常実行での実行速度, この二つの速度の比較を行う 題材として行うのはhelloworldを出力するだけのプログラムとフィボナッチ数列の例題である. 実験結果 \begin{table}[H] \begin{center} \begin{tabular}{|l|l|} \hline Language& Time \\ \hline 通常実行 & 0.2695 sec \\ 提案手法 & 0.0238 sec \\ \hline \end{tabular} \end{center} \caption{通常実行と提案手法の速度比較} \end{table} 提案手法は通常実行に比べて約10倍早い実行結果になった