March 12, 2017

デヂエのExcel化

數年にわたって會社の案件管理にデヂエを使用していたが、この年度末をもってその運用を停止することになった。理由はいろいろある。もともとはデヂエ好きのお偉い方の「これで部門閒の情報共有の圓滑化をせよ!」との號令で始まったものだ。そんな偉い方の指示ならば、その構築やメンテナンスをみんなが協力して行なうべきと思うが、デヂエの機能だけでは實現できないことまでやろうとしたため、ふと氣付くと自分1人で面倒をみるハメになっていた。そこで「このままでは私が居なくなったら面倒をみる人が居なくなってしまうから、誰か私と同じように面倒を見れる人を立ち上げていく必要があるのではないか?」と問題提起した。それが周圍には「もう疲れたからやめたい」と聞こえたらしく、一氣に運用停止に向かって話が進んでしまったのだ。

私個人は今のロケーションに居るうちは本來業務と竝行で面倒をみても構わないと思っていたので、この決定にはちょっと驚いた。ただ一般的に、誰か特定の人にしか出來ないものを組織として運用するのはリスキーであると考えるのが普通だ。私の蟲の居所が惡ければ、要望がかなえられなかったり、リジェクトされたりする。しかも、本來業務が忙しいなど出來ない理由はいくらでも言える。こんな狀態を見かねての決定なのかもしれない。しかし、そうは言いつつ出てくる要望にはほとんど對應してきたし、「え?誰かそんなこと言いました?」と聞き返されることまでやったつもりだ。そのため、デヂエ本來のセールスポイントである「プログラミング無しで構築できるWEBデータベース」が霞んでしまい、誰にでも容易にメンテナンス出來るシロモノではなくなってしまっていた。

これはシステム構築をする上での敎訓にすべきであるが、分かっていてもなかなか實踐できていない。組織がシステムを導入する場合、箱モノのソフトを買ってきて、あれこれ試しながらどうやって現在の業務に馴染ませていくかを考え、タイミングを見計らってパチッと切り替える、というのが一番安上がりなのは理屈上誰でもわかっている。しかし、90年代から始まった基幹業務のシステム化は、今に至ってもなおペーパーレス化の域を出ていないというのが現實だ。したがって、システムを導入する企業が最初に氣にするのは業務フローの效率化ではなく、システムが表示する畫面や帳票を使用中の紙の傳票や帳票にどこまで合わせられるか、ということになる。つまり傳票や帳票は會社や組織によって千差萬別であり、最初から箱モノのソフトで對應するなんてことは眼中にないのだ。そして、高額な構築費と關係者の多大な時閒と勞力を費やして完成したシステムはたった5年で更改を餘儀なくされる。5年も經てば、少なくともハードウェアやOSがサポート切れになる。さらにタイミングによってはカスタマイズのベースとなった業務パッケージソフトの壽命が終わっている場合もある。それにより、更改にもかかわらずイニシャルに近いコストがかかってしまうことが少なくない。

簡單に言えば、システムに對する投資は初期構築の1囘だけではないということだ。運用が始まれば保守費などのランニングコストがかかり、法改正に影響を受けるのであればその都度費用が必要になる。しかも、パッケージをカスタマイズしてしまうと、法改正對應のパッチを適用できなくなり、カスタマイズに近い費用が必要になってしまう。問題なのは、初期構築時にそういう說明を十分にしないまま、客に言われるがままにカスタマイズしてしまうことだ。まるでアリ地獄に引きずり込むかのように。

以上のようなことを考慮して、デヂエのようなWEBデータベースを有效活用するのは非常に賢明なことであると思う。そして、その賢明なデヂエにもいずれ終わりは來るのだ。終わる時にすべきはデヂエの中に蓄積した情報のエクスポートである。デヂエのデータベースをCSV形式やXML形式で出力するのは簡單だ。問題なのはデータベースの中にファイルを添付している場合である。普通にCSV形式で出力すると添付ファイルの項目はファイル名になる。これでは出力したCSVをExcelで開いても、その添付ファイルへのリンクにはならない。前置きがかなり長くなったが、その添付ファイルをリンクにするための方法を紹介するのがこの記事の主旨である。

デヂエのデータベースの項目はフィールドIDで定義されている。そのIDはXMLファイルを見ると分かるようになっている。しかし、添付ファイルの本體はライブラリID、フィールドIDの階層で切られたフォルダの中にレコードIDをファイル名にして格納されている。これはファイル名の衝突を避けるための方法のひとつなのだろう。これを分かり易くするためにライブラリID、レコードID、フィールドIDという階層にフォルダを切って、實際のファイル名で格納するようにしてみたのが以下のプログラムである。


Ws000135

最初の2つの變數はトップディレクトリを定義する。top-dirはデヂエのデータフォルダで、この配下にライブラリID每のフォルダがある。save-dirは添付ファイルを格納するフォルダのトップで、この配下にライブラリID/レコードID/フィールドID/添付ファイルが作られる。

Ws000136

csv-picker2はデヂエのCSVを讀み込む。各フィールドがダブルクォートで圍まれ、フィールドの中の改行にも對應している。ただし、デヂエのデータ特有の條件(最初のフィールドがレコード番號)を使用しているので他のCSVに流用することは出來ない。一般化するのであれば、ダブルクォートの内か外かを認識するロジックが必要だろう。

Ws000141

get-filesはライブラリID、レコードID、フィールドID、元のフルパスファイル名、格納先フルパスファイル名をリスト化する。

Ws000142

make-files-dirはget-filesで作成したリストを元に格納先フォルダを作成する。

Ws000143

record-file-copyはget-filesで作成したリストを元に添付ファイルを格納先フォルダにコピーする。

Ws000144

get-file-fieldは添付ファイルの各項目のフィールドIDと項目名をリスト化する。

Ws000145

make-excelはメイン處理で、添付ファイルの各項目を格納先のフルパスファイル名に置換して、CSVファイルに出力する。

*scratch*に適當に書いていたものをまとめただけなので、あまり效率的でないと思われるが見直す氣はない。一應ソースはgithubにdedie2excel.elというファイル名であげておいたので、もしも使いたいと思った人はそちらをアクセスしてください。


| | Comments (0) | TrackBack (0)

January 22, 2017

Emacs Threads 20170122

先月からちょこちょこ作っているTASKクラスであるが、最底邊の部分がある程度出來た氣がする。ちょっと前までcondvar(條件變數)の部分が動かなくて、スタブみたいな感じになっていたが、Emacsが改修されて動くようになったので、本來の處理に變えてみた。

Ws000103


TASKクラスというのはEmacsThreads機能をラッピングする。スレッドを起動するとそれに關するリソースを變數に設定しておかなければならないが、何も考えずにやるとどんどんグローバル變數がトッ散らかっていくので、そうならないようにクラス定義して管理しようとする試み。自分の都合で作っているだけなので、一般的でも、抽象的でも、普遍的でも、效率的でもない。

Ws000104


Ws000105


こんな感じのテストプログラムで自分のイメージ通りに動くことを確認したが、まだこれが何の役に立つのか自分でも分かっていない。この先、このライブラリを使って何かプログラムを書いていけば、どんどん變わっていく可能性が高い。既にcondvarの部分はまだ動作確認しているだけの狀態である。また、mutexcondvarをスレッド每に作る必要があるのか?という、かなり根本的な疑問もある。ただ、スレッドに付けた名前でアクセス出來るという手輕さくらいはある。

スレッドプログラミングはむずかしいという人が多いが、それは不必要性に比例してむずかしくなっていくと思われる。ここはスレッドを起動して多重化した方が良いと漠然と思える部分に使用するのが賢いやり方で、必要もないのに見榮でスレッドを使うような場合にはなかなか思い通りにはならないだろう。當たり前の話だが、必要性を感じないということはイメージしにくいということであり、どう動くかイメージ出來なければ正常動作を確認しようがないからだ。

ソースを見たいという奇特な人は以下のURLからどうぞ(笑)
https://github.com/nobulin

| | Comments (0) | TrackBack (0)

January 15, 2017

Emacs Threads 20170115




condvarのテストが初めて期待する結果になった。emacs/test/src/thread-tests.elを見てみると、新たにcondition-waitをテストする記述が追加されている。普通こういうのって動作する前から無きゃいけないと思うんだけど、なんで後付けなんだろう(笑)

| | Comments (0) | TrackBack (0)

January 03, 2017

Emacs Threads 20170103

大晦日にEmacscondvarについて書いた。その後、mutexのオーナーが自スレッドかどうかのチェックを、mutexの作成者かどうかのチェックと勘違いしていたため、それを踏まえて再確認した。

Ws000093

これが今囘使用するテストプログラム。自前のタスクライブラリを使用して、condition-waitを呼び出すだけの無名關數をスレッドとして起動する。

Ws000094

上記のテストプログラムをgdbから起動したEmacsで動かすことにする。その方がクラッシュしたり、知らないうちにスレッドがexitしてしまったりしても、すぐに氣付くことが出來る。

Ws000095

pop-to-bufferのところまで實行してみた。ログにはcondition-waitを呼び出す手前のメッセージが出ており、condition-waitの中で止まっているようである。この部分は事前に詳細に追いかけてみたが、實際にはpthread_cond_waitの中でブロックされている。

Ws000096

gdbの畫面を見るとスレッド(LWP 6279)が1個增えているのが分かる。

Ws000097

その後、condition-notifyを呼び出すと同時にスレッドが1exitする。この部分も事前にステップ實行しているが、なにせスパゲッティコードのような動き方をするので、よく分からない。正常に動作したのであれば「Recieve Notify」というメッセージがログに表示されるはずであるが、その前にスレッドがexitしてしまっている。何となくではあるが、pthread_cond_waitからリターンしてきたあと、longjmpし、cleanup處理(unwind-protectのような動き)をして、run_thread關數を終わっているようだ。つまり、何らかの囘復可能なエラーが起きたものと思われる。

Ws000098

上のソースはcondition-wait關數の中でpthread_cond_waitsys_cond_wait)を呼び出している部分である。その少し手前でcondvarに關連するmutexをアンロックし? pthread_cond_waitには別のロック(src/thread.cの中のstatic變數)を渡している。これはpthreadライブラリを直接使用する、他のCプログラムサンプルとかなり異なる手順に見える。まあ、それでもちゃんと動いてくれれば良いのだが。というか、そもそもcondition-waitってexit待ちじゃないよね?(笑)

| | Comments (0) | TrackBack (0)

December 31, 2016

Emacs Threads 20161231

開發中のEmacsが實裝するCondition Variable(條件變數)について、TRONのタスク閒通信を思い出しながら數日閒あれこれ試していたが、今もその機能がイメージ出來ないし、サンプルレベルのプログラムも動いていない。そもそもpthreadライブラリのことを全く知らないで理解しようとしていることに無理があると思われるが、それにしても不可解なことが多い。最も不可解なのはcondvarmutexの關係。

pthreadライブラリのC言語サンプルを見ると、同じcondvarmutexを使用してpthread_cond_waitpthread_cond_signalを呼び出している。もちろんこの2つのライブラリ關數を呼び出すのは別々のスレッドであることが前提である。1個のスレッドの中でこの2つを呼び出すのは無駄以外の何物でもない。通常、以下のような動きをイメージするのではないだろうか。

①スレッド#1はスレッド#2の處理を待つため、condition-waitを呼び出す(ブロックされる)。
②スレッド#2はスレッド#1と同期をとる準備が出來たので、condition-notifyを呼び出す。
condition-waitの中でブロックされていたスレッド#1が動きだす。

上記のスレッド#1とスレッド#2はともに同じcondvarmutexを使用する。①でスレッド#1がブロックされるのはスレッド#2に制御を渡すため。スレッド#1はスレッド#2が動いてくれないと待っていても何ら狀況は變わらない。C言語のサンプル(なんとOracleのページ)はたとえば次のような感じだ。

Ws000089


このC言語ソースを見ると、condvarmutex1個ずつあるだけであり、さらに外側のロックに指定しているmutexpthread_cond_waitに渡しているmutexも同じものである。そしてdecrement_count關數の中では、count變數が0の閒、pthread_cond_waitを呼び出し、count0でなくなったらcountから1を引く。なので、pthread_cond_waitの中では一時的にmutexを離し、increment_count關數が動けるようにする。increment_count關數の中でpthread_cond_signalmutexを渡していないのは、それをライブラリの中で離す必要がないからだ...と想像する。

しかし、Emacsの現時點のthreads機能ではcondition-waitcondition-notifyも、内部でmutexのオーナー(make-mutexによりmutexを生成したスレッド)が自スレッドかどうかをチェックしている。これすなわち、condition-waitcondition-notifyで同じcondvarを指定するとエラーになるということになってしまう。もちろん、別々のcondvarを指定すればエラーにはならないが、それだとcondition-waitから戾ってこない。まだ開發中だから意圖的にそうしているだけなのか、それとも現時點で既に正しい機能になっており、私個人がただ勘違いしているだけなのか。

まあemacs-26がリリースされれば、これらの疑問はすべて解決するのだろう。そこで今はcondvarを使用せずに同期するサンプルを書き、動作することを確認した。同じ方法で、start-taskの方式も變更している。スレッドの處理全體をwith-mutexで圍むのはどう考えても不自然なので。ちなみに同期用にはcondvarのための變數を使用している。condvarの機能が理解出來たら置き換えれば良いし、最惡分からなくてもたぶん支障はない。

Ws000088_3

Ws000090

Ws000091


129日にスレッド機能がリリースされて以來、約20日閒の成果が上に示したtask-lib.elである。まだ變わるかもしれないEmacsの機能を直接呼ぶよりも、一皮被せておいた方が良いということでTRONのシステムコールを參考に作成したものだ。taskというクラスを定義して、スレッド閒で共有する情報をまとめている。pthreadライブラリに慣れている人にはかえって分かりにくいかもしれないが、私にとってはこっちの方がしっくりくるようだ(笑)

| | Comments (0) | TrackBack (0)

December 29, 2016

Emacs Threads 20161229

2016年も本業でいろいろとEmacs Lispelisp)のプログラムを書いた。いずれも汎用的なものではないので公表はしないが、もしelispを書けなかったらどうするんだろうと考えると正直ゾッとする。

それを一番痛感するのはログ解析ではないだろうか。ログにはいろんなものが存在しテキスト形式のものに限っても、それを出力する機器、システムによって千差萬別なのだ。もちろん、EXCELで開いてソートしたり、フィルターしたりするだけでサマライズ出來るものは良いが、そうで無い場合は集計處理しない限り見れたものではない。そういうときに、ログを讀み込んで必要な情報を取り出し、それを集計するスクリプトを書くのにelispは大活躍する。さらに、マルチスレッドのサポートで大量のログもCPUパワーを最大限使用して、效率的に處理出來るようになりつつある。

以前から、なんでもかんでもマルチスレッドにすれば良いというものではないと書いてきた。深夜帶に動かして朝までに出來ていれば良いバッチ處理を、11秒速くするためにマルチスレッドにする必要はないというのが持論ではあるが、その場ですぐに結果を出す必要があるものに關しては速いに超したことはない。ということで、elispをマルチスレッドで動かすノウハウは嗜みとして掴んでおいた方が良いと考えている。私が贊成出來ないのは、別に順序立ててやれば良いだけの處理を、わざわざスレッドに分けて竝行實行し、それらのスレッドを思い通りに制御するのに苦心することだ。そんな不自然なことをしようとすれば、難しいに決まっている。

數日前に、マルチスレッドで自作のコマンドが動くことを確認出來たわけだが、これは「さあ動け!」とスレッドをバカバカ起動して野放しにするのではなく、決まった數だけ同時起動し、さらに合圖があるまで處理の開始を待たせ、すべてのスレッドが終わるのを確認する、という制御を行なっている。それでも個々のスレッドは意外に獰猛な動きをしようとする。論理CPU3個しかないのに1020もスレッドを起動しても動くはずがないのだ。

合圖があるまで處理を開始しないようにするには、ロックを掴んでスレッドを起動し、スレッドの先頭でロックを待てばよいだけだ。これは割と簡單でイメージ通りの動きをしてくれる。しかし、今のところはまだ狀態變數(Condition Variable)の使用方法が分からないままだ。これに關しては、まだ機能確認中である。

Ws000086


上のサンプルは、引數で指定した囘數だけロックを掴んでデバッグメッセージを出力するという簡單な處理を3個スレッド起動して動かしたものである。メインのスレッドでは、3個のスレッドを起動して、それらが生存している閒、それぞれのロックを順番に0.5秒ずつ解放しているだけ。子スレッド(親子關係はない)側でも0.5秒スリープしているので、たまに他の子スレッドよりも進行が遲れることがあり得、結果的に終了するタイミングがずれている。つまりループの先頭で0.5秒待って、ロックを取りに行ったらさらに0.5秒待たされたということになる。

こういうサンプルを通じて、徐々にelispのスレッド機能を把握出來ていくと思う。こういうのは、初めて魚を下ろすときの感覺に似ている。意味のある結果を出そうとするとなかなか手が出せないが、手を出さなければ絕對に出來るようにならないというヤツだ(笑)

| | Comments (0) | TrackBack (0)

December 25, 2016

Emacs Threads 20161225-2

前の記事で書いたように、たくさんのファイルに對して同樣の處理をする場合に、それをスレッドにしたらどうかと考えるのは當然である。たまたまちょっと前に作った自作版のfind-grepがあったのでそれをマルチスレッド化してみた。前の記事に載せたtaskライブラリも多少變更している。

Ws000083

Ws000084


處理の流れとしては、まず再歸しないfindloop版を呼び出してファイルのリストを作成し、そのファイル11個にスレッドを起動してgrepする。すべてのファイルの處理が終わったら、それぞれの結果を1個のバッファに收集する。論理CPU3の假想マシンなので、grep處理の多重化も3にしている。さほど惱む點はなかったが、一應動いた後でファイル每に作るバッファが殘ってしまうのを修正した。

これまで、スレッドを起動してsit-forしたり、メッセージを出したりするだけのサンプルだったが、やっとマルチスレッドっぽい處理を書いて、それが動くことも確認できたので少しホッとした(笑)

| | Comments (0) | TrackBack (0)

Emacs Threads 20161225

「あんたクリスマスなのに何やってんの?」とかいうツッコミは來ないと思うので、氣にせずEmacsThreads遊び(笑)

Ws000080


ちょっと前に、thread-nameを使ってスレッドに强引に引數を渡しフォームを實行する、with-threadというマクロを冗談で檢討していたんだけど、スレッドの起動引數はグローバルで良いんじゃない?というご尤もなご指摘をいただいた。しかし、スレッドをいくつも使う場合にそれらへ渡す引數をどんどんグローバル變數にしていくとトッ散らかって收拾がつかなくなるのは目に見えているので、クラス化してみようというのが今囘の試み。全然整理されていないように見えるのは、まだ完成形でないからであるが、いつものように完成させようなんて思っちゃいない。

create-taskという關數でmy-threadをスレッドとして生成し、start-taskでスレッドの處理を開始させ、スレッドの終了を見屆けるという、最も初步的なハンドリングが出來ることを確認した。その樣子をdebug-bufferに表示している。おそらく、現在のEmacs Threadsの仕樣ではスレッドを適切にハンドリングすれば、安全に實行することが可能になるが、突き詰めるとそれってスレッド使わなくてもイイんじゃね?ってことになりかねない。つまり、作成過程で動かしながらスレッドの實行を交通整理していくと、どんどんconcurrencyが薄くなっていくという皮肉に陷るのだ(笑)

このことはちょっと前に書いた「マルチスレッド貧乏性」でも觸れている。どんな頭の良い人でも複數のことを竝行で考えることが出來ないので、コンピュータ上でいくつものスレッドが任意に竝行で動いている狀態をイメージすることが出來ない。それをイメージしなければならないのであれば、いくつスレッドがあったとしても、そのうちのどれか1個だけ(または同樣の閉じた處理が複數)動いている狀態を作り出すことにならざるを得ないのだ。

まあでも、全く有效性がないというわけでもない。makeコマンドだって-jオプションで複數のコンパイルを竝行で行なうわけで、スクリプト處理においてもそれに類する、たとえば100個のファイルに對して全く同じことをするという場合に、それをわざわざ順番に1個ずつ處理しなければならないわけではなく、竝行で行なっても良いのであろう。それ以外に、人がイメージ出來る竝行處理ってあるのかどうか、私には分からない。

| | Comments (0) | TrackBack (0)

December 23, 2016

Emacs Threads 20161223

sit-forするスレッドを2個起動するだけでクラッシュしていたのが、こんなサンプルが動くようになったかもしれない...こんな言い方になるのは、まだ安定していないからだ。もちろん、やっていることがおかしいのかもしれないが、假に閒違っていたとしてもEmacs自體がクラッシュしてはいけないはず。

Ws000079


なぜか分からないが、後から起動したスレッドからのメッセージが先に出る。これが意圖した順序通りに表示されるとクラッシュすることが多い。さらに、my-thread-2からのExitが時閒通りに出ないこともある。こんなふうに腫れ物に觸るように試していると、本來スレッドを起動してやりたいことが浮かんでこない。やっぱりまだそういう段階ではないということか。

Emacsは衰退しました」という記事が話題になっている。20172月にリリースされるglibcに、Emacsを根底からひっくり返すような變更が入るらしい。おかげでVimmerは大喜び。勝ったとか言ってるし。何が嬉しいのか分からないが、人の不幸を喜ぶとは品が無い。

| | Comments (0) | TrackBack (0)

December 20, 2016

Emacs Threads 20161220


Ws000078


昨日示したコードは今日時點でまだ安定動作しないようなので、もしかしたらmutexcond-varを使って巧くハンドリングしてやるとより安定動作すると期待しつつ、でもプロセス制御ならこんなに氣樂に出來るんだよなあって思ってしまった。どれかプロセスを終了させようと思えば、list-processesdをタイプするだけ。

ちなみに、上に示したコードはeval-bufferで實行できるように書いたつもりが、最初のうちnoninteractiveで括るのを忘れていて、topコマンドで表示されるプロセスリストが一瞬にして全部emacsになってしまい、毛穴が開く思いをした(笑)

| | Comments (0) | TrackBack (0)

より以前の記事一覧