PowerShellでWin32APIを使うのが思った以上に大変だった

特に日本語ソースの場合、以下のblogのコードを使ってWin32APIを扱う場合が多いようですが
どうもPowerShell5.0の環境では動きません。New-PTypeの時点でダメです

PowerShellからWin32APIを呼ぶ
http://d.hatena.ne.jp/ps1/20080312/1205339720

 

pinvoke_failure

なんで、別のサイトから引っ張ってきました

New-PInvoke
http://poshcode.org/1409

んで、New-PInvokeでWin32APIのFindWindowを登録してみたのですが、
どうもStringBuilderがusingしてないって怒られます

HWND FindWindow(
    LPCTSTR lpClassName,    // クラス名
    LPCTSTR lpWindowName    // ウインドウ名(キャプション)
);
↓
New-PInvoke user32 "IntPtr FindWindow(StringBuilder lpClassName,StringBuilder lpWindowName)"

stringbuilder_error

なんで、以下のように変更(おしりに-UsingNamespaceを追加)

53:$type = Add-Type -PassThru -Name "PInvoke$(Get-Random)" -MemberDefinition $MemberDefinition
↓
53:$type = Add-Type -PassThru -Name "PInvoke$(Get-Random)" -MemberDefinition $MemberDefinition -UsingNamespace @("System.Text")

そしたら成功しましたとさ

findwindow_success

win-sshfsのleakを直してみた3

ハンドルリーク対策のロジック(ハンドル数トリガーで明示的にGC)をさらに追加して経過観察中。

ハンドル数の上昇は押さえ込めていて、win-sshfsのフリーズも起きていない。

ハンドル数の上限値はwin-sshfsの動作不良が起きる1000程度より全然上なので、ハンドル数が直接ではなくそれに付随するオブジェクトかなんらかのリソースの枯渇で動作停止が起きていると思います。

ある程度経過観察をして、ハンドル数トリガーの明示GCで本当に解決するか見極めます。

win-sshfsがフリーズするってのは、ダウンロードしてインスコして、一日くらい放置すれば確実にフリーズ(win-sshfsで作ったドライブにアクセスできない)して、運がよければブルースクリーンも見れると思うので、興味がある人はやってみてください。

しかし、明示GCで解決しちゃうってそんなのでいいのかという個人的な感想もありますが、こういう常駐アプリだと、明示的にGCするロジックいれなきゃいけないのかと少し納得する気持ちもある。

ハンドルリークってなるとハンドルのcloseし忘れだろうとプログラマーなら思うけど、明示的GCで解決するってことはプログラムロジック的には問題がない(closeし忘れではない)っていう落とし穴で解決しにくい問題かと。

win-sshfsのleakを直してみた

以前仕事で使っていたwin-sshfs(https://code.google.com/p/win-sshfs/)ですが、かなり頻繁にブルースクリーンになるので、調べてみたらどうもイベントハンドルがリークしていたみたいです。

google検索(win-sshfs ブルースクリーン)
https://www.google.co.jp/search?hl=ja&q=win-sshfs&lr=lang_ja&gws_rd=ssl#lr=lang_ja&hl=ja&tbs=lr:lang_1ja&q=win-sshfs%E3%80%80%E3%83%96%E3%83%AB%E3%83%BC%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3

なんか他の人たちもこまってるみたいだったので、修正してGitHubでPullRequestしておきました。

・リーク修正fork版

https://github.com/stofu1234/win-sshfs/tree/fixed_event_handle_leak

修正前 30分でハンドル数273→2113まで青天井に上がる

修正後 30分間ハンドル数406~681をいったりきたり

・修正前

winsshfs_leak

・修正後winsshfs_noleak

・解析中画面

handleleak

ProcessExplorerと画面のHandle.exe+Powershellでみてたところ、どうもEventHandleが増減しているようでした

Powershellでサービスを作れるようにしてみた

表題の通り、Powershellでサービスを作れるライブラリをGituhubに公開してます

PowerPuppet
https://github.com/stofu1234/PowerPuppet

C#のWrapperがPowershellを呼び出す動作が操り人形みたいなんでこんな名前にしました。

Qiitaにも投稿しようとおもうんですが、Readme.mdとあんまり内容が変わんないで投稿ためらってます。

Qiitaだったらもっとシンプルに、別の観点(ソフト仕様はどうでもいいから、サービスを動作させる事に特化させる)
で説明しなきゃいけないはずなんですが・・・

PowerShellでWPFしたい Part2 – XAML編 を実行してみた

ぎたらっち先生の

PowerShellでWPFしたい Part2 – XAML編http://tech.guitarrapc.com/entry/2013/03/14/190337

を実行してみました。

そのまま実行してみると動きませんでした。


New-Object : コンストラクターが見つかりませんでした。型 System.Xml.XmlNodeReade
r の適切なコンストラクターが見つかりません。
発生場所 行:41 文字:18
+ $reader=(New-Object System.Xml.XmlNodeReader $xaml)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (:) [New-Object], PSArgumentExce
ption
+ FullyQualifiedErrorId : CannotFindAppropriateCtor,Microsoft.PowerShell.C
ommands.NewObjectCommand

“Load” に複数のあいまいなオーバーロードがあります。引数の数は “1” です。
発生場所 行:42 文字:9
+ $window=[Windows.Markup.XamlReader]::Load( $reader )

まず、上記のエラーが出てきました。ので、アセンブリが読み込めないのかなと思って

[Reflection.Assembly]::LoadWithPartialName(“System.Xml.XmlNodeReader”)
とアセンブリ読み込んでも同じエラーメッセージがでます。

なので、次はコード削って実行しました。

xmlns="<a href="http://schemas.microsoft.com/winfx/2006/xaml/presentation">http://schemas.microsoft.com/winfx/2006/xaml/presentation </a>"
xmlns:x="<a href="http://schemas.microsoft.com/winfx/2006/xaml">http://schemas.microsoft.com/winfx/2006/xaml </a>"

PS C:\tmp> $loadXaml =@'
>> > xmlns="<a href="http://schemas.microsoft.com/winfx/2006/xaml/presentation">http://schemas.microsoft.com/winfx/2006/xaml/presentation </a>"
>> xmlns:x="<a href="http://schemas.microsoft.com/winfx/2006/xaml">http://schemas.microsoft.com/winfx/2006/xaml </a>"
>> Title="Test XAML / Show System Time"
>> FontFamily="consolas"
>> Height="350"
>> Width="400"
>> Margin="5"
>> >
>>
>> '@
>>
PS C:\tmp> [xml]$xaml = $loadXaml
値 " <Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="htt
p://schemas.microsoft.com/winfx/2006/xaml
"
Title="Test XAML / Show System Time"
FontFamily="consolas"
Height="350"
Width="400"
Margin="5"
>
" を型 "System.Xml.XmlDocument" に変換できません。エラー: "'<'
(16 進数値 0x3C) は無効な属性文字です。 行 2、位置 20。"
発生場所 行:1 文字:1
+ [xml]$xaml = $loadXaml
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : MetadataError: (:) [], ArgumentTransformationMet
adataException
+ FullyQualifiedErrorId : RuntimeException

すると別のエラーになって、ダブルクォート二つ書いてるあたりが無理があるのかと思いました。

XAML 名前空間および WPF XAML の名前空間の割り当て
https://msdn.microsoft.com/ja-jp/library/ms747086(v=vs.110).aspx

なので、MS本家のXAML呼び出し方法を実行。


xmlns="<a href="http://schemas.microsoft.com/winfx/2006/xaml/presentation">http://schemas.microsoft.com/winfx/2006/xaml/presentation </a>"
xmlns:x="<a href="http://schemas.microsoft.com/winfx/2006/xaml">http://schemas.microsoft.com/winfx/2006/xaml </a>"



xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:custom="clr-namespace:SDKSample;assembly=SDKSampleLibrary">

にしてみたら動きました。参考までに
(xmlスキーマの呼び出しに、xml使うのは環境によっては若干無理があるみたいです。)

尚、当方の環境はWindows7のPSVersion4.0です。

java8用のasync/awaitライブラリを作ってみた

java8用のasync/awaitライブラリを作ってみた!

https://github.com/stofu1234/kamaitachi

C#のasync/awaitが糖衣構文でコンパイラ拡張が必須なのは知ってるけど、

コルーチンをstatemachineで表現するところをlamda式で表現できたら、

コンパイラ拡張いらないね、という発想で実験してみたらできてしまいました。

1.インターバルで呼び出される処理全てがブロックされない

2.awaitの後の処理もUIスレッドのような特殊な1スレッドで実行される

を満たしているので、たぶんできていると思います。

3月は忙しいので、4月になったらもう少しまとめてqiitaあたりに投稿しようと思います。

とりあえず今は、ライブラリ中にあるSwingAwaiterTester.javaの実行結果を貼り付けときます。

3/15追記 やっぱコード抜粋も貼り付けときます。詳細はgitをみてください。~Tester.javaが使用例・サンプルになってます

C# async/await

   async Task<int> AccessTheWebAsync(){ 
        HttpClient client= new HttpClient();
        var urlContents= await client.GetStringAsync("http://msdn.microsoft.com");
       return urlContents.Length;
    }

Java kamaitachi async/await

    //LikeWebApplicationTester.java
    BlockingQueue<Integer> AccessTheWebAsync() {
       HttpClient client = new HttpClient();
       return awaiter.await(
            () -> client.GetStringAsync("http://msdn.microsoft.com"),
            urlContents -> {
                return urlContents.length();
            });
    }

SwingAwaiterTester.java実行結果

main start!

synchronous stack test start!
2015-03-07 23:30:51.165 Main Thread start:AWT-EventQueue-0 0 sec
2015-03-07 23:30:51.206 doHeavyWork start. AWT-EventQueue-0
2015-03-07 23:30:56.207 doHeavyWork done. AWT-EventQueue-0
2015-03-07 23:30:56.207 afterHeavyWork start. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:30:56.207 afterHeavyWork done. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:30:56.207 Main Thread done.:AWT-EventQueue-0 1 sec
2015-03-07 23:30:56.207 Neighbor Thread start:AWT-EventQueue-0 0 sec
2015-03-07 23:30:56.208 Neighbor Thread done:AWT-EventQueue-0 1 sec
2015-03-07 23:30:57.171 Main Thread start:AWT-EventQueue-0 1 sec
2015-03-07 23:30:57.172 doHeavyWork start. AWT-EventQueue-0
2015-03-07 23:31:02.172 doHeavyWork done. AWT-EventQueue-0
2015-03-07 23:31:02.172 afterHeavyWork start. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:02.173 afterHeavyWork done. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:02.173 Main Thread done.:AWT-EventQueue-0 2 sec
2015-03-07 23:31:02.174 Neighbor Thread start:AWT-EventQueue-0 1 sec
2015-03-07 23:31:02.174 Neighbor Thread done:AWT-EventQueue-0 2 sec
2015-03-07 23:31:02.176 Main Thread start:AWT-EventQueue-0 2 sec
2015-03-07 23:31:02.176 doHeavyWork start. AWT-EventQueue-0
2015-03-07 23:31:07.177 doHeavyWork done. AWT-EventQueue-0
2015-03-07 23:31:07.177 afterHeavyWork start. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:07.177 afterHeavyWork done. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:07.177 Main Thread done.:AWT-EventQueue-0 3 sec
2015-03-07 23:31:07.178 Neighbor Thread start:AWT-EventQueue-0 2 sec
2015-03-07 23:31:07.178 Neighbor Thread done:AWT-EventQueue-0 3 sec
2015-03-07 23:31:07.179 Main Thread start:AWT-EventQueue-0 3 sec
2015-03-07 23:31:07.179 doHeavyWork start. AWT-EventQueue-0
2015-03-07 23:31:12.180 doHeavyWork done. AWT-EventQueue-0
2015-03-07 23:31:12.180 afterHeavyWork start. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:12.181 afterHeavyWork done. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:12.181 Main Thread done.:AWT-EventQueue-0 4 sec
2015-03-07 23:31:12.182 Neighbor Thread start:AWT-EventQueue-0 3 sec
2015-03-07 23:31:12.182 Neighbor Thread done:AWT-EventQueue-0 4 sec
2015-03-07 23:31:12.183 Main Thread start:AWT-EventQueue-0 4 sec
2015-03-07 23:31:12.183 doHeavyWork start. AWT-EventQueue-0
2015-03-07 23:31:17.183 doHeavyWork done. AWT-EventQueue-0
2015-03-07 23:31:17.183 afterHeavyWork start. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:17.184 afterHeavyWork done. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:17.184 Main Thread done.:AWT-EventQueue-0 5 sec
2015-03-07 23:31:17.185 Neighbor Thread start:AWT-EventQueue-0 4 sec
2015-03-07 23:31:17.185 Neighbor Thread done:AWT-EventQueue-0 5 sec
2015-03-07 23:31:17.186 Main Thread start:AWT-EventQueue-0 5 sec
2015-03-07 23:31:17.186 doHeavyWork start. AWT-EventQueue-0
2015-03-07 23:31:22.187 doHeavyWork done. AWT-EventQueue-0
2015-03-07 23:31:22.187 afterHeavyWork start. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:22.187 afterHeavyWork done. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:22.187 Main Thread done.:AWT-EventQueue-0 6 sec
2015-03-07 23:31:22.188 Neighbor Thread start:AWT-EventQueue-0 5 sec
2015-03-07 23:31:22.188 Neighbor Thread done:AWT-EventQueue-0 6 sec
2015-03-07 23:31:22.191 Main Thread start:AWT-EventQueue-0 6 sec
2015-03-07 23:31:22.191 doHeavyWork start. AWT-EventQueue-0
2015-03-07 23:31:27.191 doHeavyWork done. AWT-EventQueue-0
2015-03-07 23:31:27.191 afterHeavyWork start. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:27.192 afterHeavyWork done. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:27.192 Main Thread done.:AWT-EventQueue-0 7 sec
2015-03-07 23:31:27.192 Neighbor Thread start:AWT-EventQueue-0 6 sec
2015-03-07 23:31:27.193 Neighbor Thread done:AWT-EventQueue-0 7 sec
2015-03-07 23:31:27.195 Main Thread start:AWT-EventQueue-0 7 sec
2015-03-07 23:31:27.195 doHeavyWork start. AWT-EventQueue-0
2015-03-07 23:31:32.196 doHeavyWork done. AWT-EventQueue-0
2015-03-07 23:31:32.196 afterHeavyWork start. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:32.196 afterHeavyWork done. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:32.197 Main Thread done.:AWT-EventQueue-0 8 sec
2015-03-07 23:31:32.197 Neighbor Thread start:AWT-EventQueue-0 7 sec
2015-03-07 23:31:32.198 Neighbor Thread done:AWT-EventQueue-0 8 sec
2015-03-07 23:31:32.200 Main Thread start:AWT-EventQueue-0 8 sec
2015-03-07 23:31:32.200 doHeavyWork start. AWT-EventQueue-0
2015-03-07 23:31:37.201 doHeavyWork done. AWT-EventQueue-0
2015-03-07 23:31:37.201 afterHeavyWork start. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:37.202 afterHeavyWork done. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:37.202 Main Thread done.:AWT-EventQueue-0 9 sec
2015-03-07 23:31:37.202 Neighbor Thread start:AWT-EventQueue-0 8 sec
2015-03-07 23:31:37.203 Neighbor Thread done:AWT-EventQueue-0 9 sec
2015-03-07 23:31:38.204 Main Thread start:AWT-EventQueue-0 9 sec
2015-03-07 23:31:38.204 doHeavyWork start. AWT-EventQueue-0
2015-03-07 23:31:43.204 doHeavyWork done. AWT-EventQueue-0
2015-03-07 23:31:43.204 afterHeavyWork start. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:43.204 afterHeavyWork done. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:43.205 Main Thread done.:AWT-EventQueue-0 10 sec
2015-03-07 23:31:43.205 Neighbor Thread start:AWT-EventQueue-0 9 sec
2015-03-07 23:31:43.206 Neighbor Thread done:AWT-EventQueue-0 10 sec
2015-03-07 23:31:43.206 Main Thread start:AWT-EventQueue-0 10 sec
2015-03-07 23:31:43.206 doHeavyWork start. AWT-EventQueue-0
2015-03-07 23:31:48.208 doHeavyWork done. AWT-EventQueue-0
2015-03-07 23:31:48.208 afterHeavyWork start. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:48.209 afterHeavyWork done. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:48.209 Main Thread done.:AWT-EventQueue-0 10 sec
asynchronous stackless test start!
2015-03-07 23:31:50.212 Main Thread start:AWT-EventQueue-0 0 sec
2015-03-07 23:31:50.216 Main Thread done.:AWT-EventQueue-0 0 sec
2015-03-07 23:31:50.216 Neighbor Thread start:AWT-EventQueue-0 0 sec
2015-03-07 23:31:50.216 Neighbor Thread done:AWT-EventQueue-0 1 sec
2015-03-07 23:31:50.271 doHeavyWork start. pool-1-thread-1
2015-03-07 23:31:51.216 Main Thread start:AWT-EventQueue-0 0 sec
2015-03-07 23:31:51.216 Main Thread done.:AWT-EventQueue-0 0 sec
2015-03-07 23:31:51.217 Neighbor Thread start:AWT-EventQueue-0 1 sec
2015-03-07 23:31:51.217 Neighbor Thread done:AWT-EventQueue-0 2 sec
2015-03-07 23:31:51.252 doHeavyWork start. pool-1-thread-2
2015-03-07 23:31:52.217 Main Thread start:AWT-EventQueue-0 0 sec
2015-03-07 23:31:52.217 Main Thread done.:AWT-EventQueue-0 0 sec
2015-03-07 23:31:52.218 doHeavyWork start. pool-1-thread-3
2015-03-07 23:31:52.218 Neighbor Thread start:AWT-EventQueue-0 2 sec
2015-03-07 23:31:52.218 Neighbor Thread done:AWT-EventQueue-0 3 sec
2015-03-07 23:31:53.218 Main Thread start:AWT-EventQueue-0 0 sec
2015-03-07 23:31:53.218 Main Thread done.:AWT-EventQueue-0 0 sec
2015-03-07 23:31:53.218 Neighbor Thread start:AWT-EventQueue-0 3 sec
2015-03-07 23:31:53.222 Neighbor Thread done:AWT-EventQueue-0 4 sec
2015-03-07 23:31:53.265 doHeavyWork start. pool-1-thread-4
2015-03-07 23:31:54.219 Main Thread start:AWT-EventQueue-0 0 sec
2015-03-07 23:31:54.219 Main Thread done.:AWT-EventQueue-0 0 sec
2015-03-07 23:31:54.220 doHeavyWork start. pool-1-thread-5
2015-03-07 23:31:54.223 Neighbor Thread start:AWT-EventQueue-0 4 sec
2015-03-07 23:31:54.223 Neighbor Thread done:AWT-EventQueue-0 5 sec
2015-03-07 23:31:55.220 Main Thread start:AWT-EventQueue-0 0 sec
2015-03-07 23:31:55.221 Main Thread done.:AWT-EventQueue-0 0 sec
2015-03-07 23:31:55.221 doHeavyWork start. pool-1-thread-6
2015-03-07 23:31:55.224 Neighbor Thread start:AWT-EventQueue-0 5 sec
2015-03-07 23:31:55.224 Neighbor Thread done:AWT-EventQueue-0 6 sec
2015-03-07 23:31:55.272 doHeavyWork done. pool-1-thread-1
2015-03-07 23:31:56.221 Main Thread start:AWT-EventQueue-0 0 sec
2015-03-07 23:31:56.221 Main Thread done.:AWT-EventQueue-0 0 sec
2015-03-07 23:31:56.225 Neighbor Thread start:AWT-EventQueue-0 6 sec
2015-03-07 23:31:56.225 Neighbor Thread done:AWT-EventQueue-0 7 sec
2015-03-07 23:31:56.225 doHeavyWork start. pool-1-thread-1
2015-03-07 23:31:56.225 afterHeavyWork start. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:56.225 afterHeavyWork done. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:56.280 doHeavyWork done. pool-1-thread-2
2015-03-07 23:31:57.222 Main Thread start:AWT-EventQueue-0 1 sec
2015-03-07 23:31:57.222 Main Thread done.:AWT-EventQueue-0 1 sec
2015-03-07 23:31:57.226 Neighbor Thread start:AWT-EventQueue-0 7 sec
2015-03-07 23:31:57.226 Neighbor Thread done:AWT-EventQueue-0 8 sec
2015-03-07 23:31:57.226 afterHeavyWork start. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:57.226 afterHeavyWork done. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:57.224 doHeavyWork start. pool-1-thread-2
2015-03-07 23:31:57.245 doHeavyWork done. pool-1-thread-3
2015-03-07 23:31:58.223 Main Thread start:AWT-EventQueue-0 2 sec
2015-03-07 23:31:58.223 Main Thread done.:AWT-EventQueue-0 2 sec
2015-03-07 23:31:58.223 doHeavyWork start. pool-1-thread-3
2015-03-07 23:31:58.227 Neighbor Thread start:AWT-EventQueue-0 8 sec
2015-03-07 23:31:58.227 Neighbor Thread done:AWT-EventQueue-0 9 sec
2015-03-07 23:31:58.227 afterHeavyWork start. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:58.228 afterHeavyWork done. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:58.265 doHeavyWork done. pool-1-thread-4
2015-03-07 23:31:59.224 Main Thread start:AWT-EventQueue-0 3 sec
2015-03-07 23:31:59.224 Main Thread done.:AWT-EventQueue-0 3 sec
2015-03-07 23:31:59.224 doHeavyWork start. pool-1-thread-4
2015-03-07 23:31:59.228 Neighbor Thread start:AWT-EventQueue-0 9 sec
2015-03-07 23:31:59.228 Neighbor Thread done:AWT-EventQueue-0 10 sec
2015-03-07 23:31:59.228 afterHeavyWork start. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:59.228 afterHeavyWork done. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:31:59.279 doHeavyWork done. pool-1-thread-5
2015-03-07 23:32:00.225 Main Thread start:AWT-EventQueue-0 4 sec
2015-03-07 23:32:00.225 Main Thread done.:AWT-EventQueue-0 4 sec
2015-03-07 23:32:00.225 doHeavyWork start. pool-1-thread-5
2015-03-07 23:32:00.229 Neighbor Thread start:AWT-EventQueue-0 10 sec
2015-03-07 23:32:00.229 Neighbor Thread done:AWT-EventQueue-0 11 sec
2015-03-07 23:32:00.229 afterHeavyWork start. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:32:00.229 afterHeavyWork done. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:32:00.282 doHeavyWork done. pool-1-thread-6
2015-03-07 23:32:01.225 doHeavyWork done. pool-1-thread-1
2015-03-07 23:32:01.226 Main Thread start:AWT-EventQueue-0 5 sec
2015-03-07 23:32:01.226 Main Thread done.:AWT-EventQueue-0 5 sec
2015-03-07 23:32:01.226 doHeavyWork start. pool-1-thread-1
2015-03-07 23:32:01.230 Neighbor Thread start:AWT-EventQueue-0 11 sec
2015-03-07 23:32:01.230 Neighbor Thread done:AWT-EventQueue-0 12 sec
2015-03-07 23:32:01.230 afterHeavyWork start. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:32:01.230 afterHeavyWork done. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:32:01.230 afterHeavyWork start. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:32:01.230 afterHeavyWork done. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:32:02.227 Main Thread start:AWT-EventQueue-0 7 sec
2015-03-07 23:32:02.227 Main Thread done.:AWT-EventQueue-0 7 sec
2015-03-07 23:32:02.227 doHeavyWork start. pool-1-thread-6
2015-03-07 23:32:02.232 Neighbor Thread start:AWT-EventQueue-0 12 sec
2015-03-07 23:32:02.232 Neighbor Thread done:AWT-EventQueue-0 13 sec
2015-03-07 23:32:02.275 doHeavyWork done. pool-1-thread-2
2015-03-07 23:32:03.229 Main Thread start:AWT-EventQueue-0 7 sec
2015-03-07 23:32:03.229 Main Thread done.:AWT-EventQueue-0 7 sec
2015-03-07 23:32:03.229 doHeavyWork start. pool-1-thread-2
2015-03-07 23:32:03.233 Neighbor Thread start:AWT-EventQueue-0 13 sec
2015-03-07 23:32:03.233 Neighbor Thread done:AWT-EventQueue-0 14 sec
2015-03-07 23:32:03.233 afterHeavyWork start. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:32:03.233 afterHeavyWork done. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:32:03.280 doHeavyWork done. pool-1-thread-3
2015-03-07 23:32:04.225 doHeavyWork done. pool-1-thread-4
2015-03-07 23:32:04.230 Main Thread start:AWT-EventQueue-0 8 sec
2015-03-07 23:32:04.230 Main Thread done.:AWT-EventQueue-0 8 sec
2015-03-07 23:32:04.230 doHeavyWork start. pool-1-thread-4
2015-03-07 23:32:04.234 Neighbor Thread start:AWT-EventQueue-0 14 sec
2015-03-07 23:32:04.234 Neighbor Thread done:AWT-EventQueue-0 15 sec
2015-03-07 23:32:04.234 afterHeavyWork start. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:32:04.234 afterHeavyWork done. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:32:04.234 afterHeavyWork start. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:32:04.234 afterHeavyWork done. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:32:05.231 Main Thread start:AWT-EventQueue-0 10 sec
2015-03-07 23:32:05.231 Main Thread done.:AWT-EventQueue-0 10 sec
2015-03-07 23:32:05.231 doHeavyWork start. pool-1-thread-3
2015-03-07 23:32:05.235 Neighbor Thread start:AWT-EventQueue-0 15 sec
2015-03-07 23:32:05.235 Neighbor Thread done:AWT-EventQueue-0 16 sec
2015-03-07 23:32:05.284 doHeavyWork done. pool-1-thread-5
2015-03-07 23:32:06.235 Main Thread start:AWT-EventQueue-0 10 sec
2015-03-07 23:32:06.235 Main Thread done.:AWT-EventQueue-0 10 sec
2015-03-07 23:32:06.235 Neighbor Thread start:AWT-EventQueue-0 16 sec
2015-03-07 23:32:06.235 Neighbor Thread done:AWT-EventQueue-0 17 sec
2015-03-07 23:32:06.235 afterHeavyWork start. AWT-EventQueue-0 hogeratta!!
main end!
2015-03-07 23:32:06.235 doHeavyWork start. pool-1-thread-5
2015-03-07 23:32:06.235 afterHeavyWork done. AWT-EventQueue-0 hogeratta!!
2015-03-07 23:32:06.253 doHeavyWork done. pool-1-thread-1
2015-03-07 23:32:07.228 doHeavyWork done. pool-1-thread-6
2015-03-07 23:32:08.274 doHeavyWork done. pool-1-thread-2
2015-03-07 23:32:09.255 doHeavyWork done. pool-1-thread-4
2015-03-07 23:32:10.231 doHeavyWork done. pool-1-thread-3
2015-03-07 23:32:11.265 doHeavyWork done. pool-1-thread-5

Powershellのループ処理が遅いと思ったので6

Sedによる文字列置換(ファイル読み込み・書き込みあり)をPowershellで再現したコードが遅すぎるという話(このシリーズ、パイプの処理速度全般に関して書いてるんですけど、前回と今回は比較対象がsedのような処理)

前回は
パイプのかわりにBlockingQueueをバッファとしてファイル読み込み・文字列置換・差いる書き込みをするコマンドレットを作ってみたところ、最大で6.3倍になった。(C#コマンドレットをPowershellから起動)

今回はF#でパイプ処理を書いてみようと思います

・今回のF#コード


open System
open System.Collections.Concurrent
open System.Threading.Tasks
open System.IO
open System.Text
open System.Threading.Tasks
open System.Text.RegularExpressions

非同期cat関数(テキストファイルをBlockingCollectionとして読み込む)

let cat (encoding :string) (filename :string) =
let output =new BlockingCollection()
let encoding = Encoding.GetEncoding(encoding)
use reader = new StreamReader(filename,encoding)
let mainLoop =
let mutable line=""
while line null do
line mainLoop))
mainLoopTask |> ignore;
output;;

|||| 並列パイプ

let ( |||| ) (input : BlockingCollection) (fx: ( 'TI -> 'TO)) =
let output =new BlockingCollection()
let mainLoop =
while not input.IsCompleted do
let line=input.Take();
if line null then
output.Add(fx line)
let mainLoopTasks = [| for i in 1 .. Environment.ProcessorCount -> Task.Factory.StartNew(Action (fun () -> mainLoop)) |]
let terminate =
Task.WaitAll mainLoopTasks
output.CompleteAdding()
let teriminateTask =
Task.Factory.StartNew(Action(fun () ->terminate))
teriminateTask |> ignore;
output;;

||||> 非同期リダイレクト

let ( ||||> ) (input : BlockingCollection) (filename :string) =
let encodeString = "utf-8"
let encoding = Encoding.GetEncoding(encodeString)
use writer = new StreamWriter(filename,false,encoding)
let mainLoop =
while not input.IsCompleted do
let line = input.Take()
if line null then
writer.WriteLine(line);
let mainLoopTask =
Task.Factory.StartNew(Action(fun () ->mainLoop))
mainLoopTask

sync関数

let sync ( task :Task ) =
task.Wait()

エントリーポイント

[]
let main argv =
cat "utf-8" @"c:\tmp\evtlog.csv" |||| ( fun line -> Regex.Replace(line,"イベント","お弁当")) ||||> @"c:\tmp\evtlog7.csv" |> sync
0 // 整数の終了コードを返します

・ベンチ結果
# powershell パイプライン
PS D:\Users\naomasa\Documents\Visual Studio 2013\Projects\ParalellPipeline\Paral
ellPipeline\bin\Debug> 1..5 | % {(Measure-Command {cat c:\tmp\evtlog.csv | ? { $
_ -replace “イベント”,”お弁当”} | Out-File c:\tmp\evtlog8.csv -encoding utf8}).T
otalMilliseconds}
17412.2273
17407.1302
18177.021
17622.5944
17464.0425

# F#パイプライン
PS D:\Users\naomasa\Documents\Visual Studio 2013\Projects\ParalellPipeline\Paral
ellPipeline\bin\Debug> 1..5 | % {(Measure-Command {.\ParalellPipeline.exe}).Tota
lMilliseconds}
626.2075
582.9214
605.5008
581.5356
580.3243

F#のパイプラインだと平均29.6倍 早くなりました

今回、F#の演算子定義を使って、パイプを定義。
バッファリングにBlockingQueue使っているので並列処理もできる。
(ただし、並列だと出力順序は保障されない)

テストに使用した論理8コアのPCにあわせて、8並列での処理になっているが、最初のPowershellのコードに比べて30倍弱の速度が出た。

当方のパイプの定義は、Unixのパイプをイメージしています。F#というかO’Camlのもともとのパイプ(|>)は関数(Function)と同義でバッファリングがないです。
(Unixのパイプはバッファリングがある。参考資料1の項目「実装」参照)
なので、F#のパイプにBlockingCollectionのバッファを付け足してみました、という実装になっています。
BlockingCollectionはスレッドセーフ(むしろそれをメインで使う)なので、非同期・並列処理をがしがしやってる今回のコードになりました。
(なので、今回の||||を並列パイプ ParalellPipeと呼んでます)

非同期・並列を惜しみなく投入して、かつF#を使った(F#の元になったO’Camlは非常に高速な処理系)ので
今回のようなベンチ結果になったとお思います。

・参考資料1
パイプ (コンピュータ)
http://ja.wikipedia.org/wiki/%E3%83%91%E3%82%A4%E3%83%97_(%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF)