概要
- 最近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%フォルダに配置するようにして優しく隠蔽。
- 自分自身をexecで起動するように修正して単一化。
- 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)