yamicha.com's Blog - Presented by yamicha.com
Blog yamicha.com's Blog - 2018/11 の記事
[1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23] [24] [25] [26] [27] [28] [29] [30]

yamicha.com's Blog
 諸事情により、現在更新休止中。ご了承ください。もし今後ブログを再開することがあるとすれば、その際にはこのブログスクリプトではなく、新しく開発したものによるかもしれません。
 当ブログ管理者についてはこちらをご参照。
開発魔法(737)
社会問題(733)
お知らせ(11)
質問・バトン回答(15)
ゲスト出演(8)
経済・知的財産(150)
ゲーム開発(182)
[Ada] 勝手に補足
- Note
- 金配りの次の一手


- Endless Ultimate Diary
- 銃世界

漢字バトン
- うるる雑記帳
- 漢字接力棒

ツキアイゲノムバトン
- ブログ@うにうに画像倉庫
- あぶ内閣

縺イ縺セ縺、縺カ縺励ヰ繝医Φ
- 月夜のボヤキ
- 騎士サーラバトン
パスワードを使う
名無し (2012/02/27)


開発者解放裁判
yamicha.com (2010/03/14)
Winnyに関しては、私も「純白」とまでは考えておりませんし、使用し..

開発者解放裁判
通りすがり (2010/03/08)
winnyに関しては「ダウンロードソフト板」なんてところを拠点に開発..

新型インフルエンザの恐怖
いげ太 (2009/11/03)
> C#などの「int Some(int , int)」は、F#では「(int * int) ->..

時効に関する思考
yamicha.com (2009/08/31)
>いげ太さんコメントありがとうございます。手元にドキュメントが少..
Homepage
Blog Top
Normal View
List View
Search
Calendar
Comment List
Trackback List
Blog RSS
Send Trackback
Phone Mode
Administrator
yamicha.com
Blog
るううるる。
Source
法令データ提供システム
FindLaw
Development
Java2 Platform SE 6
Java EE 6 API
MySQL Developer Zone
PHP Reference
MSDN Library
Ada Reference Manual
Objective Caml
Python Documentation
Erlang
Prolog Documents
因縁をつける
2007/09/07(Fri)18:38:55
 神奈川県警の巡査長が高校生を暴行し、傷害罪で逮捕された問題。当初報道されたところによれば、「電車内で高校生が悪ふざけをしており、巡査長がそれをとがめて顔を平手打ちした」とのことでした。この経緯を見る限りでは、暴力を振るったことは問題ですが、巡査長の行為には正当性があるように見えます。実際、県警には「殴ったのは悪いが逮捕はやりすぎ」「マナー違反を注意できない世の中になる」「寛大な処分を」などといった声が大量に寄せられたようです。
 ところが、その後の県警の追加会見により、先の会見の内容は事実と異なることが分かりました。いくつかの記事を当たってみたところ、どうやら以下の経緯が正解のようです。なお、逮捕された巡査長の小磯氏は当時おそらく非番であり、あえて「巡査長」と表記すべきかは疑問ではありますが、ここでは分かりやすさを考えて「巡査長」と表記します。

1.高校生の少年が電車内でピストル型ライターを出して構え、車掌らに注意を受ける。少年は「分かりました」とそれに従い、ライターをかばんにしまう。
2.酒を飲んだ帰りの小磯巡査長、先に注意された少年が友人らと談笑しているのを見て「反省していない」と勝手に思い込む。
3.少年と同じ駅で下車した後、階段でいきなり少年の髪をつかみ、路上に連れ出して顔を平手で殴打。そればかりか、少年によれば「ライターの柄で鼻を殴られた」とのこと(小磯巡査長曰く「ライターを取り出した際に鼻に当たった」)。その間、少年は驚きのあまり無抵抗。
4.それを見とがめた人が仲裁に入るも、「こういうガキは殴らないと分からない」と暴言を吐き、その後も顔を殴打。

 上記の流れが確かなら、これは一方的に小磯巡査長の傷害行為です。
 まず、少年は車掌らに注意された際、車掌らに暴言を吐いたり注意を無視するわけでもなく、注意に従ってライターをかばんにしまっています。また、「悪ふざけ」が破壊行為、暴力行為、チカンなどであるならまだしも、ただ単にピストル型ライターを構えてみせただけであり、極めて悪質とまではいえないものです。そもそも悪質性の高い悪ふざけを行っているなら、少年は車掌らの判断で下車させられるか、現行犯逮捕されていたでしょう。
 ところが、それを見ていた小磯巡査長は勝手に「少年は反省していない」と判断し、いきなり髪を引っ張ったり顔を殴打するなどの暴行を働いたのです。「下車後に少年に話しかけた際、反省していないと答えたので殴った」などといった事情があるならともかく、問答無用で路上に連れ出して殴打したわけですから、当初言われていたような「注意」といったレベルではなく、はっきり言って弁解の余地はありません。
 ではなぜこのような誤解を招くかといえば、最初の会見が明らかな誤りであったのと同時に、「巡査長」という肩書きに正義を連想する人が多いためでしょう。要するにこの事件は「酒を飲んだ帰りの乗客が、同様に乗客で気に入らない少年を殴打した」という内容なのです。小磯巡査長がどれほど酒を飲んでいたかは定かではありませんが、言うなれば酔っ払いが少年に因縁をつけ、いきなり顔を殴りつけたということです。
 私が今回の事件で疑問視するのはまさにこの点です。無論、この事件が当初の会見通りの内容であれば、殴打した人物が巡査長でなくても支持する声は多かったものと考えられます。こうした意味では、小磯巡査長の寛大な処分を要請した人々に罪はありませんし、当初の情報では理解できる行為ではあります。しかし、日本人はどういうわけか非常に肩書きに弱く、それが結果的に今回の「誤解」を招く一因になったことは否定できません。
 今回の事件を起こしたのは巡査長でしたが、これが仮に以下のような報道であったとしたなら、受け手はどのような印象を持つでしょうか。

 少年が電車内でライターをもてあそんでいたため、これを暴力団員が注意しようとしたところ口論となり、同暴力団員が少年の顔面を殴打した。

 この場合、被疑者を擁護する声はずっと少なくなると考えられます。「暴力団員」はさすがに極端であるとしても、「巡査長」以外の肩書きを当ててみると良く分かります。警官だろうが弁護士だろうが犯罪者は存在します。無論、大多数の警官や弁護士が善良であることは言うまでもありませんが、それは一般の国民にしても同じです。問題は日本国民がいかに肩書きに踊らされているかということです。
 以前、これも確か横浜辺りの事件であると記憶していますが、医師が配偶者と子どもを殺害し、死体を遺棄するという事件がありました。この際、実は犯人であった医師は当初「悲劇の人物」として扱われたらしく、元FBIのレスラー氏は著書内で「日本人は医師(など、一般に「地位が高い」とされる人物)を疑わない」ことを指摘しています。
 今回の事件の場合、当初の会見内容が明らかに事実に反していたことがそもそもの原因ですから、小磯巡査長を擁護する意見が直接「肩書きに弱い」ことに結びつくわけではありません。しかしながら、恐ろしいのは被疑者の行為が正当かどうかのボーダーにあるような事件です。肩書きが一定以上なら無罪放免か寛大な処分、そうでなければ重罪などということがあってはなりません
 当然、いい加減な会見を行った県警にも問題があります。もし事実を把握していて、かつ最初の会見を開いたのだとすれば、身内をかばっていると指摘されても文句は言えません。逆に、会見後の調べで事実が分かったのであれば、最初の会見では不確かでいい加減な情報を流したということです。加害者及び被害者の双方の言い分を取り上げるならともかく、あの会見ではあまりに一方的過ぎます。
 もう1つ、これだけ大量の巡査長擁護意見が寄せられたからには、おそらくちまたのブログにも同様の意見を述べた記事が存在するものとみられます(私が購読しているブログには今のところ存在しません)。実は私も「暴力は良くないが、車内でのマナーの悪さを注意したのであれば評価できる面もある」といった記事を書くことを検討していました。当然のことながら、被疑者が「暴力団員」の場合はともかく、犯罪組織以外の一般市民であれば同様の記事を書くことを検討したでしょう。
 小磯巡査長を擁護した記事に問題があるなどと言うつもりはありません。問題があるとすれば、誤った情報を流した当初の会見の方です。しかし、この膨大なインターネットの世界の中には、小磯巡査長を擁護するばかりかこのような一方的な情報に基づいて少年を誹謗中傷したブログも存在するものと考えられます。
 まさか「ライターを取り出したが、車掌らに注意されてそれに素直に従った少年に対し、いきなり髪をつかんで顔を殴打することは悪くない」などと開き直った主張をするブログはさすがに存在しないと考えられますが、いくら当初流れていたのが誤った情報であるとはいえ、その誤報を基に少年を誹謗中傷したブログは果たして記事の撤回と謝罪を行うでしょうか。もしこれがある程度まともなマスコミであれば、いい加減な情報を基にした記事で誹謗中傷を行ってしまったわけですから、少年の名誉回復と誤報の訂正のために謝罪と撤回を行うことになります。しかし、同様に誹謗中傷を行ったブログ作成者はこれと同じ対応を取るでしょうか。
 いくらブログが手軽なツールであるとはいえ、無責任な情報を垂れ流しっぱなし、事実に基づかない誹謗中傷の訂正も謝罪もなしでは、これまた無責任な新聞社連中に「インターネットはD級、E級のメディア」などと言われても反論できません。私はそうしたブログを購読しておらず、また購読するつもりも一切ないため、少年を中傷するような記事が存在するのか、またそうしたブログが誤報が分かった後に中傷を謝罪・撤回するかどうかについて直接知るすべはありませんが、この点は少々気になります。

 迷走の自民党。何とも意味不明なことに、郵政民営化反対者として切ったはずの平沼氏を再び招き入れようとしています。しかも弱り目の自民党は完全に足元を見られ、氏に落選離党者5名を「誓約書」なしで復党させるという要求を突きつけられています。
 当然、自民党はこれで良いのでしょうが、反発する国民は多いようです。「反対者を切って郵政民営化をするということで支持を集め、与党が議席の2/3を獲得したにもかかわらず、都合が悪くなれば今度は復党させるようでは筋が通らない」というわけです。とはいえ、先の郵政選挙は単なる低IQ選挙であり、民意であるとは言いがたい面もありますし、そもそも安倍内閣はそういう内閣ですから仕方がありません。
 そして、もはや安倍内閣のジンクスとなったのが「農相は必ず内閣を去る法則」。このブログで松岡氏自殺を取り上げたのが2007/5/29付の記事です。それから3ヶ月少々しか経っていないにもかかわらず、松岡氏を含めて今の農相は4人目です。いつから閣僚は月交代になったのでしょう。そればかりか、環境相、少子化相など様々な面々が不正に明け暮れている始末です。
 さらに、選挙後はさすがに多くの閣僚が口をつぐんでいるようですが、選挙前には爆弾発言が大量に飛び出しました。やれ「産む機械」「2人以上出産する健全な欲求」、やれ「原爆しょうがない」。閣僚連中の行動を見ても、無我夢中で無賃残業合法化制度を導入しようとするなど国民のことを考えていないのは明らかですし、選挙に大敗して少しは懲りたかと見ていれば、こうした閣僚らをまとめるリーダーが「美しい国」などという愚かな絵空事を未だに真剣に考えているというこっけいさ。多くの人はあきれていることでしょう。
 なぜこのような状況になるのか。理由は簡単、本来最もやめるべき人間が未だにポストにかじりついているためです。それが誰であるかは言うまでもないでしょう。自民党の議員の多くもその辺はすでに見越しているらしく、先のことを考えたり、解散総選挙がなされた時のために準備を整えたりしているようです。
 安倍内閣は今後何もできぬまま消え去るとして、問題はその先です。野党が参院を押さえたおかげで、とりあえず愚法は通せなくなるでしょうが、これでは停滞が避けられません。安倍内閣に法を通されるよりは停滞の方が明らかに日本のためになりますが、安倍内閣が消え去った後もこの状態が続くのは健全ではありません。
 民主党は参院第一党の座を確保し、名実ともに二大政党の片方となりましたが、それでもなお党自体を一発で壊滅させる方法があります。やり方は簡単、単に自民党と大連立を組むだけで良いのです。自民党もその辺は承知しているらしく、やはりと言うべきか、水面下ではそうした工作が活発化しているようです。今のところ民主党は大連立に応じない姿勢ですが、応じればその時が最後です。そうした意味では、民主党が大連立に応じないことも一応の争点となるでしょうか。
 ともかく、まずは安倍内閣の終焉からです。内閣自体が消える前にあと何人の閣僚が消えるか、予想してみるのも面白いかもしれません。

 Java SE 7では機能拡張されるらしいNew I/O。FTPもNew I/Oの対象になるなど、色々と変わるようです。
 それでNew I/Oとは何ぞや。1.4で導入された機能ですから割と以前からあるものですが、今のところ以下のような機能をサポートしています。7ではさらに色々追加されそうです。

・様々なプリミティブ型のバッファ
・メモリにマップしたファイルを扱う機能
・ブロックしないソケット
・「ネイティブな」配列

 それでは、最も簡単なNew I/Oを。
IntBuffer buf = IntBuffer.allocate(5);
buf.put(1).put(2).put(4).put(8).put(16);

buf.rewind();

out.println(buf.get());	// 1
out.println(buf.get());	// 2
out.println(buf.get());	// 4
out.println(buf.get());	// 8
out.println(buf.get());	// 16
 get()またはput()するたびにインデックス位置が増加していきます。InputStream同様、mark()でマーク付けし、reset()でマークまで飛ぶこともできます。インデックスはrewind()で先頭に戻すことができ、position(int)で好きな位置に置くことができます。通常、延々とget()を呼び出していけば、イテレータのように値を順番に手に入れることができます。ただし、最初にIntBuffer.allocate()で配列のサイズを指定していますが、これはArrayListなどと違って拡張されることはなく、これを超える要素にはアクセスできません。
 BufferにはIntBufferの他にも様々な種類があり、特にByteBufferは特殊な機能をいくつか備えています。また、CharBufferはCharSequenceをインプリメントしており、CharSequenceを要求するメソッドに渡すなど、文字列として扱うことができます。
 次はメモリにマップしたファイルを扱ってみるとしましょうか。なお、APIドキュメントによれば「数十キロバイトのファイルを扱う程度なら通常のread/writeの方が速くなる場合が多い」とのこと。性能を発揮するにはそれなりのファイルサイズが必要ということでしょうか。
 そういうわけで試してみたのが以下のコードです。少なくとも1.5MB以上あるファイルを用意し、それを1024バイトずつ配列にコピーする行為を1500回繰り返す(合計1.5MBを読み取る)のに何ミリ秒を必要とするかを計測します。
byte b[] = new byte[1024];
File file = new File("filename");

// 普通の読み込み
long io_start = new Date().getTime();

FileInputStream fis = new FileInputStream(file);

for(int i = 0; i < 1500; i++)
	fis.read(b);

fis.close();

long io_end = new Date().getTime();

// NIO
long nio_start = new Date().getTime();

fis = new FileInputStream(file);
FileChannel fc = fis.getChannel();
MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY , 0 , file.length());

for(int i = 0; i < 1500; i++)
	mbb.get(b);

fis.close();

long nio_end = new Date().getTime();

out.println("IO:" + (io_end - io_start));
out.println("NIO:" + (nio_end - nio_start));
 以下がその結果です。
IO:121
NIO:20
 この程度の規模になると、New I/Oによるメモリマッピング読み込みの方が明らかに速いことが分かります。これを複数回実行してみたところ、IOの速度は40〜50ミリ秒の間になりましたが、NIOは10〜20ミリ秒をキープし続けます。
 ただし、読み込む量が少ない場合、例えば上記ならループが300回程度であれば、通常のIOの方が速くなります。メモリマッピングで速度が向上するのはあくまで大きなファイルを扱う場合に限られます。
 ちなみに、実は上記のテストコードはフェアではありません。というのは、上記の方法でファイルの中身を残らず読み取りたい場合、InputStreamなら-1が返るまでread()し続ければ良いのですが、ByteBufferで存在するデータ以上のバイトまで読み込もうとすると例外が投げられます。これを回避するには、インデックスの大きさをしっかり確かめつつ読み込むか、あるいは例外をキャッチしてから残りのデータを回収するしかありません。そして、これらはいずれもオーバーヘッドとなります
 それでは、上記プログラムを「ファイルを全部読み取るプログラム」に修正してみましょうか。
final int MAX = 1024;
byte b[] = new byte[MAX];

File file = new File("filename");

// 普通の読み込み
long io_start = new Date().getTime();

FileInputStream fis = new FileInputStream(file);

while(fis.read(b) != -1);

fis.close();

long io_end = new Date().getTime();

// NIO
long nio_start = new Date().getTime();

int len = (int)file.length();

fis = new FileInputStream(file);
FileChannel fc = fis.getChannel();
MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY , 0 , len);
int loop = len / MAX;
int reserve = len - loop * MAX;

for(int i = 0; i < loop; i++)
	mbb.get(b);

if(reserve > 0)
	mbb.get(b , 0 , reserve);

fis.close();

long nio_end = new Date().getTime();

out.println("IO:" + (io_end - io_start));
out.println("NIO:" + (nio_end - nio_start));
 このプログラムで2,956,919バイトのファイルを読み込んでみると、NIOが30〜40ミリ秒というなかなかの結果を示しました。IOは70〜100といったところです。byte[]のサイズを1024ではなく16384などに変えてみたりもしましたが、結果はほとんど同じでした。どうやら、NIOのメモリマッピングによるファイル読み込みはファイルサイズが大きい場合には文句なしに速いようです。
 ファイルに関する検証はこれで十分でしょう。ソケットの非ブロック読み込みは読んで字のごとくですから飛ばすとして、後は「ネイティブ配列」でしょうか。
 非常に有名な話ではありますが、Javaの配列は純粋な配列ではなくクラスに近いものです。そのため、C/C++には存在し得ないlengthプロパティで最大数を取得できますし、うっかり配列の終端以降にアクセスしてもArrayIndexOutOfBoundsExceptionがスローされるだけで済み、C/C++のようにメモリのデータを破壊してしまうことはありません。しかし、こうした機能がオーバーヘッドを招いていることも事実です。
 しかし、New I/Oの機能を使用すれば、このような「純粋な」配列を作ることができるようです。
IntBuffer buf = ByteBuffer.allocateDirect(20).asIntBuffer();
buf.put(1).put(1).put(2).put(3).put(5);
 allcateDirect()を使ってダイレクトバッファを構築します。この機能を持っているのはByteBufferのみですが、asIntBuffer()などで任意のバッファを取得することができます。任意のバッファに変換した際にはサイズが変化する(例えばintは4バイトのため、ByteBufferの1/4のサイズとみなされる)ため、注意が必要です。
 さて、果たしてこれは速いのでしょうか。バブルソートで試してみましょう。
private long bubbleSort(ByteBuffer buf){
	long start = new Date().getTime();

	int max = buf.capacity();

	boolean check = true;
	while(check){
		check = false;

		for(int i = 0; i < max - 1; i++){
			if(buf.get(i) > buf.get(i + 1)){
				byte t = buf.get(i);
				buf.put(i , buf.get(i + 1));
				buf.put(i + 1 , t);
				check = true;
			}
		}
	}

	return new Date().getTime() - start;
}

private long bubbleSort(byte buf[]){
	long start = new Date().getTime();

	int max = buf.length;

	boolean check = true;
	while(check){
		check = false;

		for(int i = 0; i < max - 1; i++){
			if(buf[i] > buf[i + 1]){
				byte t = buf[i];
				buf[i] = buf[i + 1];
				buf[i + 1] = t;
				check = true;
			}
		}
	}

	return new Date().getTime() - start;
}

final int MAX = 3000;

// バッファを生成
byte array[] = new byte[MAX];
ByteBuffer nio = ByteBuffer.allocate(MAX);
ByteBuffer direct = ByteBuffer.allocateDirect(MAX);

for(int i = 0; i < MAX; i++){
	byte rand = (byte)(Math.random() * 256);

	array[i] = rand;
	nio.put(rand);
	direct.put(rand);
}

nio.rewind();
direct.rewind();

// ソートの時間を測定
out.println("Array:" + bubbleSort(array));
out.println("ByteBuffer:" + bubbleSort(nio));
out.println("DirectBuffer:" + bubbleSort(direct));
 結果は次の通りです。
Array:381
ByteBuffer:1682
DirectBuffer:1672
 ダメではありませんか。全然速くありません。何回か試した限りでは、ByteBufferよりDirectBufferの方が多少速いことが多いものの、どういうわけかByteBufferの方が速いこともありますし、何より普通の配列に圧倒的な差をつけられています。これはもう誤差だの何だのというレベルではなく、100%勝てません。
 今回はByteBufferですからこの程度で済みましたが、intではさらにひどいことになります。DirectBufferはByteBufferでしか作れないため、これをIntBufferにするためにはasIntBuffer()による変換(ラッピング)が必要です。そして、ラップによるオーバーヘッドはDirectの性能による速度を大幅に上回っています。intの配列なら700ミリ秒で済むところを、通常のIntBufferでは2300、DirectのByteBufferをラップしたIntBufferでは3000といったことが平気で起こります。せっかくDirectにしたにもかかわらず、本気で泣けてきます。バブルソートで3000項目もソートしている以上、アクセス回数不足で性能が出ていないということはないはずですし、なかなか不可解です。
 処理回数よりも配列の個数が重要なのでしょうか。
private long access(IntBuffer buf){
	long start = new Date().getTime();

	int max = buf.capacity();
	for(int i = 0; i < max; i++){
		buf.put(i);
	}

	return new Date().getTime() - start;
}

private long access(int buf[]){
	long start = new Date().getTime();

	for(int i = 0; i < buf.length; i++){
		buf[i] = i;
	}

	return new Date().getTime() - start;
}

final int MAX = 1000000;

// バッファを生成
int array[] = new int[MAX];
out.println("Array:" + access(array));
array = null;

IntBuffer nio = IntBuffer.allocate(MAX);
out.println("IntBuffer:" + access(nio));
nio = null;

IntBuffer direct = ByteBuffer.allocateDirect(MAX * 4).asIntBuffer();
out.println("DirectBuffer:" + access(direct));
direct = null;
 配列のサイズは1,000,000、4MBにもなります。これだけあれば十分でしょう。その結果、
Array:20
IntBuffer:80
DirectBuffer:100
 全然ダメです。これではまだ足りないのでしょうか。そういうわけで、配列のサイズをさらに10倍にし、さらにDirectBufferのコードを実行する時点で上2つの分のメモリを解放するGCが呼ばれている(つまりDirectBufferにオーバーヘッドが生じている)可能性も考えて、DirectBufferの処理を1番最初に持ってきました。結果はこの通り。
DirectBuffer:1312
Array:240
IntBuffer:1012
 やはりダメです。本来ならIntBufferよりDirectBufferの方が高速でなければならないのですが、多少の高速さよりもラッピングのオーバーヘッドの方が大きいようです。
 それではオーバーヘッドがない場合はどの程度の性能になるのでしょうか。intをbyte、IntBufferをByteBufferとして、配列のサイズを10,000,000にして実行すると、次のような結果が得られました。
Array:170
ByteBuffer:952
DirectBuffer:861
 繰り返し実行していくと、おおむねこの辺りの数値が出るようになりました。
Array:151
ByteBuffer:751
DirectBuffer:721
 今回はByteBufferとDirectBufferにそれなりの違いが現れています。10回試してみたところ、9回はDirectBufferの方が速かったため、ByteBufferよりDirectBufferの方が高速であると結論して間違いなさそうです。しかし、その高速さはIntBufferなどでラッピングすることによるオーバーヘッドを下回る程度でしかありません。さらに、ここまで来ると言及する気も失せますが、普通の配列の方が圧倒的に速いです。
 New I/O、色々と機能は充実しているようですが、性能があまりに中途半端すぎるため、使いどころに迷います。SE 7での機能強化が待たれます。
カテゴリ [開発魔法][社会問題] [トラックバック 0][コメント 0]
<- 前の記事を参照 次の記事を参照 ->

- Blog by yamicha.com -