LoginSignup
2

More than 5 years have passed since last update.

Sleep Sortでマルチスレッド比較(js/TS/VB/C#/C++/D/Go/HSP(mist))

Last updated at Posted at 2016-11-14

概要

  • 最近PromiseとかTaskとかThreadとかいくつかの処理系の非同期処理を学んだのでその対比としてSleepSortの書き比べ。
  • jsとTS、VBとC#はどうしても似通るのでそれぞれAsync/Await使用版、未使用版で分割。
    (TSとC#でAsync/Awaitを使用する)
  • HSPはそもそもマルチスレッド非対応なのでexeファイル分割してのゴリ押し対応。※参考
  • 2016/11/16 HSP mistの魔力に魅せられてSreepSort追加。
  • 2016/12/10 C++、Go言語追加。タグ? 知らないなぁ。タグ数足らん

実装

JavaScript(PromiceOnly)
const rl=require("readline")
    .createInterface(process.stdin,process.stdout);

new function main(){
    var sortResult=[];

    const delayWait=wait=>new Promise(
        resolve=>setTimeout(()=>{
            sortResult.push(wait);
            resolve();
        },wait*10)
    );

    rl.setPrompt("【SleepSort JavaScript Promise】\n> ");
    rl.prompt();
    rl.once("line",input=>{
        const items=input.split(" ");
        const itemPromises=items.map(val=>delayWait(parseInt(val,10)));

        Promise.all(itemPromises)
        .then(value=>{
            console.log("done!");
            console.log(sortResult);
            rl.setPrompt("");
            rl.prompt();
            rl.once("line",process.exit);
        });
    });
};
TypeScript(Async/Await)
import * as readline from "readline";
const rl=readline.createInterface(process.stdin,process.stdout);

(async function main(){
    var sortResult:string[]=[];

    const delayWait:(number)=>Promise<void>=async function(wait){
        await new Promise(resolve=>setTimeout(resolve,wait*10));
        sortResult.push(wait);
    };

    rl.setPrompt("【SleepSort TypeScript Async/Await】\n> ");
    rl.prompt();
    const input:string=await new Promise(resolve=>rl.once("line",str=>resolve(str)));
    const items:string[]=input.split(" ");
    const itemPromises:Promise<void>[]=items.map(val=>delayWait(parseInt(val,10)));

    await Promise.all(itemPromises);
    console.log("done!");
    console.log(sortResult);
    rl.setPrompt("");
    rl.prompt();
    rl.once("line",process.exit);
})();
VB.net(TaskOnly)
Imports System
Imports System.Console
Imports System.Threading
Imports System.Threading.Tasks
Imports System.Collections.Generic

Module Program
    Sub Main()
        Dim workMin As Integer
        Dim ioMin As Integer
        ThreadPool.GetMinThreads(workMin,ioMin)
        ThreadPool.SetMinThreads(100,ioMin)

        Dim sortResult As New List(Of String)

        Dim delayWait As Func(Of Integer,Task)=Function(wait)
            Return Task.Run(Sub()
                Thread.Sleep(wait*10)
                sortResult.Add(wait)
            End Sub)
        End Function

        Write("【SleepSort VB.NET Task】" & vbLf & "> ")
        Dim input As String=ReadLine()
        Dim items As String()=Split(input," ")
        Dim itemTasks As Task()=Array.ConvertAll(items,Function(val)delayWait(CInt(val)))

        Task.WaitAll(itemTasks)
        WriteLine("done!")
        WriteLine(" " & String.Join(", ",sortResult))
        ReadLine()
    End Sub
End Module
C#(Async/Await)
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;

class Program{
    static void Main(){
        new Func<Task>(async()=>{
            int workMin;
            int ioMin;
            ThreadPool.GetMinThreads(out workMin,out ioMin);
            ThreadPool.SetMinThreads(100,ioMin);

            List<string> sortResult=new List<string>();

            Func<int,Task> delayWait=async wait=>{
                await Task.Delay(wait*10);
                sortResult.Add(wait.ToString());
            };

            Console.Write("【SleepSort C# Async/Await】\n> ");
            string input=Console.ReadLine();
            string[] items=input.Split(' ');
            Task[] itemTasks=Array.ConvertAll(items,val=>delayWait(Int32.Parse(val)));

            await Task.WhenAll(itemTasks);
            Console.WriteLine("done!");
            Console.WriteLine(" "+String.Join(", ",sortResult));
            Console.ReadLine();
        })().Wait();
    }
}
C++(future)
#include <stdio.h>
#include <iostream>
#include <string>
#include <vector>
#include <thread>
#include <future>
#include <sstream>
using namespace std;

int main(){
    vector<int> sortResult;
    auto delayWait=[&](int wait)->future<void>{
        return async(launch::async,[wait,&sortResult]{
            this_thread::sleep_for(chrono::milliseconds(wait*10));
            sortResult.push_back(wait);
        });
    };

    cout<<"【SleepSort C++ future】\n> "<<flush;
    string input;
    getline(cin,input);

    vector<string> items;
    stringstream ss(input);
    string val;
    while(getline(ss,val,' ')){
        items.push_back(val);
    }
    vector<future<void>> itemfutures;
    for(string val:items){
        itemfutures.push_back(delayWait(stoi(val)));
    }

    for(auto &val:itemfutures){
        val.wait();
    }
    for(int i=0;i<sortResult.size();i++){
        if(i!=0){
            cout<<", ";
        }
        cout<<sortResult[i];
    }
    cout<<endl;
    getchar();
}
D言語(core.thread)
import std.stdio;
import std.conv;
import std.string;
import core.thread;
import std.windows.charset;

void main(){
    int[] sortResult;
    Thread delegate(int) delayWait=wait=>new Thread(
        delegate(){
            Thread.sleep(dur!"msecs"(wait*10));
            sortResult~=wait;
        }
    );

    write(to!string(toMBSz("【SleepSort D言語 core.thread】\n> ")));
    string input=(str=>str[0..str.length-1])(readln());
    string[] items=input.split(" ");

    auto itemThreads=new ThreadGroup();
    foreach(val;items){
        Thread th=delayWait(to!int(val));
        itemThreads.add(th);
        th.start;
    }

    itemThreads.joinAll();
    writeln("done!");
    writeln(sortResult);
    readln();
}
Go言語(Goroutine)
package main
import(
    "fmt"
    "bufio"
    "os"
    "strings"
    "strconv"
    "time"
)

func main(){
    sortResult:=[]int{}
    delayWait:=func(ch chan struct{},wait int){
        time.Sleep(time.Duration(wait*10)*time.Millisecond)
        sortResult=append(sortResult,wait)
        defer close(ch)
    }

    fmt.Print("【SleepSort Go Goroutine】\n> ")
    input:=bufio.NewScanner(os.Stdin)
    input.Scan()
    items:=strings.Fields(input.Text())
    itemsGoroutine:=[]chan struct{}{}
    for _,val:=range items {
        ch:=make(chan struct{})
        val_i,_:=strconv.Atoi(val)
        go delayWait(ch,val_i)
        itemsGoroutine=append(itemsGoroutine,ch)
    }

    for _,val:=range itemsGoroutine {
        <-val
    }
    fmt.Println(sortResult)
}
HSP(execProcess)
#packopt name "SleepSortHS"
#runtime "hsp3cl"
#include "mod_getenv.as"

#uselib "kernel32"
#func GetModuleFileName "GetModuleFileNameA" int,int,int

sdim fullExePath, 256
GetModuleFileName,varptr(fullExePath),256

ExeName=getpath(fullExePath,8)
ProcessFunc="delayWait"
sdim tempPath,256
getenv tempPath,"USERPROFILE"
itemStock=tempPath+"\\ProcessTemp"

#module Program
    #uselib "msvcrt"
    #func printf "printf" str
    #deffunc delayWait int _wait,int _PID
        await _wait*10
        notesel endProcess
        endProcess=str(_wait)
        notesave itemStock@+_PID
    return

    #deffunc main
        printf("【SleepSort HSP exec】\n> ")
        input _input,256,1
        split _input," ",items

        repeat length(items)
            exec ExeName@+" "+ProcessFunc@+" "+int(items(cnt))+" "+cnt
        loop
        sdim sortResult,,length(items)
        notesel endProcess
        ended=0
        repeat
            PID=cnt\length(items)
            exist itemStock@+PID
            if strsize<0 :continue

            noteload itemStock@+PID
            delete itemStock@+PID
            sortResult(ended)=endProcess
            ended++

            if length(items)=ended :break
        loop
        mes "done!"
        repeat length(sortResult)
            if cnt!=0:printf ", "
            printf sortResult(cnt)
        loop
        mes
        input exit,,1
    return
#global

cmd=dir_cmdline
if 0<=instr(cmd,,ProcessFunc) {
    split cmd," ",args
    delayWait int(args(1)), int(args(2))
}
else {
    main
}

HSP(mist)
#packopt name "SleepSortMS"
#runtime "hsp3cl"
#include "mist.hsp"

#module Program
    #uselib "msvcrt"
    #func printf "printf" str
    #uselib "kernel32"
    #func sleep "Sleep" int
    sleep 0

    #deffunc main
        mstOpenHspLib
        mstCaptDll
        mstBind "sortResult",sortResult
        sdim sortResult,,length(items)
        mstLoad "ended=0"
        mstCompile {"
            #deffunc delayWait int _wait
                sleep _wait*10
                sortResult(ended)=str(_wait)
                ended++
            return
        "}

        printf("【SleepSort HSP mist】\n> ")
        input _input,256,1
        split _input," ",items

        mstSetWorkerNum length(items)
        repeat length(items)
            mstThreadCall "delayWait",int(items(cnt))
        loop
        mstThreadJoin

        mes "done!"
        repeat length(sortResult)
            if cnt!=0:printf ", "
            printf sortResult(cnt)
        loop
        mes
        mstDestroy
        input exit,,1
    return
#global
main

補足

  • D言語のThreadはPromise.raceやWaitAny, WhenAnyに対応する構文がなさそう。
    この処理が必要になるケースがわかっていないけど、isRunningを観測していればいいのかな。
//tg As ThreadGroup
joinAny:for(;;){
    foreach(t;tg)if(!t.isRunning)break joinAny;
}

  多分こんな感じで。

  • D言語のreplaceの使い方がわからない。
    あとはreadlnでLFも持ってくるっぽいので文字処理必須。
  • HSPのマルチスレッドもどきはtxtファイルで待ち合わせしてるのでそのファイルに万一何か起きればバグる。
    そのためとりあえずTimeOutできるように小細工。
    • 自分自身をexecで起動するように修正して単一化。
      また、一時ファイルを%TEMP%フォルダに配置するようにして優しく隠蔽。
  • mistの魔力やばい。プラグインなのでdll(hpi)が別途必要になるけど、命令や関数が色々な形で起動できるので夢広がる。ラムダ式とかクロージャみたいな使い方もできる。一括処理だけだけどマルチスレッドにも対応してる。でも、mist空間内ではプリプロセッサ命令使えないので拡張が若干効かない部分もあるのかな。wait、awaitがmist空間内ではスレッド回してても同期処理になってしまうので代替の方法を探したけど、HSP標準のgetTime関数で再実装することしか思いつかなかった。
    • mistプラグイン作者のえくーさんにmstCaptDll命令の存在を教えて頂いた。これを使用することでmist空間内にfuncで定義したdll関数を適用できるみたいだ。ただ、その関数が読み込まれる条件がちょっとわからなくてsleepを適当なところで空撃ちさせている。

動作環境

JavaScript: node v4.3.2
TypeScript: tsc 1.8.10
VB.net: vbc 14.0.1055
C#: csc 4.6.1055.0
C++: cl 18.00.40629
D言語: dmd v2.066.1
Go言語: go 1.7.4
HSP 3.4
HSP mist ver.alpha(0x27050)

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2