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

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


#実装
```js: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);
		});
	});
};
```
```ts: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);
})();
```
```vbnet: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
```
```csharp: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();
	}
}
```
```cpp: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: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: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)
}
```
```cpp: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
}

```
```cpp: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を観測していればいいのかな。

```D:
//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)