2016年2月26日金曜日

CoreDataによる集計とインメモリ集計の比較

どうも、こんにちは。はざまです。今回は珍しく、前回の投稿からあまり日にちが空いてませんね。
さて、iOS向けお小遣い帳アプリを作っていてCoreData内に保存したデータの合計金額を算出しなければならない場面に遭遇したため、その方法についてメモしておきます。

素直に考えると、CoreData内に保存したデータの集計を行う方法には2通りあることがわかります。一つ目は、CoreDataがバックストアに使用しているSQLiteの集計関数を活用する方法。二つ目が、一旦集計を行うオブジェクトをすべてフェッチして、Swift側で集計を行う方法です。
単純に考えて、一つ目の方法の方が速度は速いでしょう。しかし、バックストアにSQLiteを使用していることから、金銭を扱うアプリでは必須とも言える10進数型での集計は行えなさそうです。今回は軽くベンチマークも取ってみたので、その辺のトレードオフも含めて、SQLite組み込みの浮動小数点型とiOS組み込みの10進数型での合計値算出方法を比較してみたいと思います。


func calculateSumUsingCoreData()
{
    let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
    let request = NSFetchRequest()
    request.entity = NSEntityDescription.entityForName("Event", inManagedObjectContext: context)
        
    let expr_description = NSExpressionDescription()
    expr_description.name = "sum"
    expr_description.expression = NSExpression(forFunction: "sum:", arguments: [NSExpression(forKeyPath: "price")])
    expr_description.expressionResultType = .DecimalAttributeType  //ここで.DecimalAttributeTypeを指定していても、結果はdoubleかfloatでしか取れない
        
    request.propertiesToFetch = [expr_description]
    request.resultType = .DictionaryResultType
        
    do {
        let results = try context.executeFetchRequest(request)
        if results.count > 0 {
            let extracted_results = results.map {(elem: AnyObject) -> Double in
                let dict = elem as! [String: Double]
                let func_reuslt = dict["sum"]
                return func_reuslt!
            }
            return extracted_results[0]
        } else {
            return 0.0
        }
    } catch {
        let ns_error = error as NSError
        print("\(ns_error), \(ns_error.userInfo)")
        return Double.NaN
    }
}

func calculateSumWithReduce()
{
    let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
    let request = NSFetchRequest()
    request.entity = NSEntityDescription.entityForName("Event", inManagedObjectContext: context)
        
    do {
        let entities = try context.executeFetchRequest(request)
        if entities.count > 0 {
            let events = entities as! [Event]
            let result = events.reduce(NSDecimalNumber(integer: 0)) { (currentTotal, event) in
                let price = event.price!
                return currentTotal.decimalNumberByAdding(price)
            }
            return result
        } else {
            return NSDecimalNumber(integer: 0)
        }
    } catch {
        let ns_error = error as NSError
        print("\(ns_error), \(ns_error.userInfo)")
        return NSDecimalNumber(integer: 0)
    }
}

合計値を算出するコードは、それぞれ以上の通りです。これを新規プロジェクトウィザードのMaster-Detail Applicationテンプレートに当て込んでベンチマークを行います。ちなみに計測を行う部分はこんな感じです。

let RepeatTimes = 10_000
func viewDidLoad()
{
    if let label = self.detailDescriptionLabel {
        let start = NSDate()
        for _ in 0..<RepeatTimes {
            _ = calculateSumUsingCoreData()
        }
        let end = NSDate()
                
        let elapsed_time = (end.timeIntervalSinceReferenceDate - start.timeIntervalSinceReferenceDate) * 1000.0
        let sum = calculateSumUsingCoreData()
        label.text = "pure core data: \(sum.description), time elapsed: \(elapsed_time)"
    }
            
    if let label2 = self.detailDescriptionLabel2 {
        let start2 = NSDate()
        for _ in 0..<RepeatTimes {
            _ = calculateSumWithReduce()
        }
        let end2 = NSDate()
                
        let elapsed_time2 = (end2.timeIntervalSinceReferenceDate - start2.timeIntervalSinceReferenceDate) * 1000.0
        let sum2 = calculateSumUsingFor()
        label2.text = "using reduce: \(sum2.stringValue), time elapsed: \(elapsed_time2)"
    }
}

集計対象のデータは、0〜100,000の整数乱数を生成して10で割り、0.0〜10,000.0までの浮動小数点数を100個としています。
ベンチマークを行う端末は、去年までメインで使用していたiPhone5Sです。
そして、その結果がこちら。

純粋CoreDataによる集計法の方が、約3.5倍速いという結果になりました。しかし、そのトレードオフとして、純粋CoreDataの方法では結果が浮動小数点数になることを忘れてはなりません。
さらに少し気になってデータ数を200個にした場合も試してみました。その結果は次の通り。
なんと今度は、CoreDataのみの方が約6.5倍も速いという結果に。(ちなみにまだApple Developer Programに登録していないため、どちらもDebugビルドでの結果になります。正式にアプリをApp Storeに公開したら、再計測してみたいと思います)
さらにさらに、データ数400個の場合。
今度は約11.2倍。結構リニアに差が開いていきます。Swiftで集計する方はメモリーの消費量もかなり大きく、シチュエーションを選びそうです。
う〜ん、よっぽどデータに偏りがない限り、CoreDataの集計関数を使えば誤差もなく十分な気がしなくもないような……

2016年2月9日火曜日

関数型プログラミングスタイルのすゝめ(後編)

前編だけ公開して、後編は眠らせたままにしていたようです。
後編の今回は、実際のコードを交えてより実践的な視点から関数型スタイルプログラミングを俯瞰してみようと思います。では、まずは以下のサンプルコードを開いてみてください。



上記のサンプルコードは、C#を使用して関数型スタイルと非関数型スタイルで0から100までの偶数を並べあげる処理を記述したものです。コメントを全て英語で記述したため、ソースコード単体だと読みにくいかもしれないですが、上から順に、forループ、foreachループ、LINQ to Objects、LINQ to SQLを使用しています。このうち、まず、本筋とあまり関係はないけど、補足が必要そうなところから解説します。
foreachループ以降のソリューションで登場する
Enumerable.Range(from, to, step=1)
メソッドは、fromからtoまでstep刻みの整数列をIEnumerableオブジェクトとして生成します。

さて、本題の関数型スタイルに入りましょう。関数型言語と聞くと、Haskellを筆頭として、C系の手続き型スタイルに慣れてしまったプログラマーにとってみると、どうしてもとっつきにくい印象を抱いてしまう人が多いことでしょう。確かに、文(値を返さない文法構造の一種)が存在せず全てを関数で処理し、関数が状態を持たないと聞くと、ついつい腰が重くなってしまいそうな気配がします。
しかし、ここでお勧めする関数型スタイルとは、C++やC#に代表されるマルチパラダイム言語においてアクセント的に使用します。そもそも、関数型言語と手続き型言語では、根本的に使用される概念も異なるため、すべてを関数型化できるわけではないですからね。

上記の例の3番目の記述法を見てみましょう。この一文、日本語として読み解くと、「even_numbers_lto(0から100までの偶数)は0から100までの整数のうち、2で割り切れる数」と解釈できます。4番目の記述法は、これをよりSQLライクに記述していると考えられます。つまり、この2文における=は、数学におけるものと同じように、等価や宣言を意味しているとも解釈できます。

前編にも記載したように手続き型言語では、プログラマの役目はコンピュータにある問題の処理方法(How -- instructions)を教えることでした。
一方、関数型言語では、Howを表すブロックが既に存在するため、これを組み合わせて(What, When)を記述することに集中することができます。この特徴から、特にビッグデータに代表されるような大量のデータを扱う場合や、手順よりも値が変化した時やユーザインタアクションがあった時にラベルの内容を変えるなど、GUIの処理を定義する際などに便利と考えられます。さらに、関数型言語の関数の特徴として副作用を持たないというものがありますが、手続き型に書くよりも宣言的に記述が行えるため、コールバックベースのGUI処理を行うよりも見通しが立ちやすいという利点もあります。

2016/2/9 23:21追記:
この意味では、リアクティブプログラミング(いい記事がなかったので、リンク先は英語版のWikipediaです)というパラダイムが考案されています。

2016年2月6日土曜日

CoreDataでdate型のattributeを使用して比較を行う

ご無沙汰しています。はざまです。新しく記事を書くのは一体何ヶ月ぶりでしょうか・・・(約1年ぶりみたいですね・・・)
さて、前置きはこのぐらいにして、本題に入りましょう。

つい先日から、Swiftを使用してiOSアプリ作成を始めたのですが、CoreDataを使用してdate型の値を扱おうとした時に少しハマった点があったので、ここにメモ代わりとして残しておこうと思います。
 以下、CoreDataの基礎は理解しているものとして記載します。

例えば、CoreDataで以下のような構造のデータを管理しているとします。
id int32,
name string,
price int32
date date

この構造のデータベースから今月追加した分の商品の情報を全件取得したいとします。CoreDataのAPIを使用すれば、次のように記述すれば目的は達成できます。

let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let request = NSFetchRequest()
let entity = NSEntityDescription.entityForName("Items", inManagedObjectContext: context)
request.entity = entity

let (this_month, next_month) = self.calculateFirstDayInMonthAndNext()
request.predicate = NSPredicate(format: "%@ <= date AND date < %@", argumentArray: [this_month, next_month])

do {
    let results = try context.executeFetchRequest(request)
...

しかし、実はこの書き方には落とし穴があります。XCodeの標準機能を使用してCoreDataのエンティティに対してモデルクラスを生成すると、date型はNSTimeInterval型としてマッピングされます。CoreDataは内部データストレージとしてSQLiteを使用しています。このSQLiteにはMySQLのdatetime型に相当する型が存在しないため、CoreDataのAPIは、NSDateに代表される日付型を、単純な基準日時からの経過時間に変換して保存します。この時、timeIntervalSinceReferenceDateプロパティを使用して変換を行うため、データの保存時にもこのプロパティを使用して変換していなければ齟齬が発生してしまい、条件にひっかからなくなってしまいます。

なお、どうしてもtimeIntervalSinceReferenceDateを使用してdate attributeの中身を上書きできない場合には、NSPredicateの中身をdate.timeIntervalSince1970などと書き換えることで、適当なNSDate型のプロパティを使用して条件指定できるようになります。既にリリース済みのアプリなどで、容易にデータ再構築ができない場合には一考する価値がありそうです。

2015年1月17日土曜日

RustとC++言語仕様比較

最近、個人的にRustという言語が熱いです。まだ、正式版リリース前なので、日本語の公式ドキュメントも存在しませんが、一言で表現するならば「Cライクな記号を使用する関数型言語」とでも言いましょうか。文法的にも見た目も、CやC++のそれに酷似しているのですが、その実、意味論的には異なる部分の方が多く、どちらかといえばHaskellに代表される関数型言語に分類されるべきかもしれません。

さて、Rustは公式にも、C++と同等程度のパフォーマンスを出しつつ、メモリセーフで並列化可能なプログラムを書くための言語として開発が進められていると書かれています。そして、実際C++と似通った概念も多いので、C++とRustの違いを明確にするため、以下にC++の概念とRustの概念を極力、対になるように列挙してみました。

mod = namespace
& = const& (Rustの参照とC++の参照は同じ。ただし、Rustはデフォルトでimmutable)
&mut = &
デリファレンスと参照化(ポインタ化)は同じ演算子でできる。宣言と演算子で意味が変わらない分、Rustの方が親切(unsafe時は、その限りではない)(C++でナマのポインタを扱う人は稀だろうから、これは当てはまらないかも)
fn method(&mut self) = void method()
fn method(&self) = void method() const
fn new() -> SomeType = SomeType() (コンストラクタは、ファクトリメソッドとして定義)
(デストラクタはfn drop(self)と書くのが通例のよう。Clone traitを実装してると挙動変わるかも?基本的にデストラクタは、スコープ外に抜けさせて作用させるので、明示的にdropするのは、RAIIを使ってる時ぐらいみたい。それも、リソースを解放するよという意思表示の意味が強そう)

fn staticMethod() -> () = static void staticMethod() (特殊変数selfを第1引数に取らないメソッドは、staticメソッドとして解釈される。Rustのコンストラクタはこの性質を利用したもの。デフォルトコンストラクタをnewと書くのは、単なる習慣みたい)

std::boxed::Box = std::unique_ptr (メモリの所有権を持つスマートポインタ)
他にもReference Countを使用したスマポもある。

/*****
use std::os;
fn main() {
    let args = os::args();
    let arg1 = match args.len() {
        1 => args[0],...
/*****
int main(int argc, char* argv[])
{
    char* arg1 = (argc == 1) ? argv[0] :...
*****/
(main関数は、引数も戻り値もなしがRust流。コマンドライン引数には、std::osモジュール経由でアクセスする)

/*****
impl Add for SomeType {
    type Result = SomeType;
    pub fn add(self, rhs: SomeType) -> SomeType {...
/*****
class SomeType
{
public:
    static SomeType operator+(SomeType rhs)
    {....
*****/
(オペレータのオーバーロードは、対応するtraitをimplすることで行う。+演算子がaddメソッド呼び出しのsyntactic sugarになっている)

(まだ追記するかも...)

2014年10月11日土曜日

isucon4の予選に出た話

久々の更新です(半年ぶりぐらい?)。はざまです。
今回は2週間前にisuconの予選に出場してきた話を書きます。珍しく日記的な記事になりそうですね。

詳細はhttp://isucon.net/を参照していただきたいのですが、isuconとは、LINEが主催するWebアプリケーションの最適化コンテストです。毎回、モック程度の小規模なWebアプリを題材にして、リソースの圧縮やインフラ回りの最適化によってある時間内にさばけるリクエスト数の多寡によって競い合うものです。
わが「あーだこーだ」は、スコア26000程度で残念ながら本戦への出場はかなわなかったのですが、my.cnfの設定やAWSのセットアップ方法など、今後に繋がりそうな収穫を多々得られたため、よしとしましょう。
技術系ブログらしい詳細の話は、後日気が向いた時にでも、記載しようと思います。

2014年3月30日日曜日

関数型プログラミングスタイルのすゝめ(前編)

え〜、半年以上ご無沙汰していたみたいですね。どうもはざまです。
今回はまた技術系ブログらしく、技術系の啓蒙文でも書いてみようかと思います。

さて、今回のテーマは「関数型プログラミングスタイル」なんですが、一体それはなんぞやという話ですよね?この名前自体は思いつきでつけただけなので、特に気にする必要はないのですが、では一体関数型プログラミングとはなんなのかという話をする前に、まず「関数」の話から始めましょう。
数学における「関数」は本来「函数」と漢字表記していました。これについて関数は、「入力を変化させる箱だ」というような解説を学生の頃に受けた記憶があるのですが、我らがWikipedia先生によると、この表記とこの説明にはなんの関連性もないらしいです・・・
さて、おぼろげになりつつある記憶をたどってみれば、この言葉を初めて聞いたのは中学校の数学の時間ではないでしょうか?その頃に出てきた関数といったら例えば、f(x) = x^2などでしょうか。この等式は、x=1,-1を代入するとf(1) = f(-1) = 1、x=2, -2を代入するとf(2) = f(-2) = 4・・・というように代入されるxによって出力となる値(この場合はf(x))が変化しました。
一般に、ある入力x,y,z...に対して一意な出力f(x,y,z...)を返す写像(平たく言えば入力に対して処理を施して出力を返す変換器)のことを関数と呼んでいます。数学の世界では入力も出力も実数になるものを実関数、両方共複素数となるものを複素関数などと呼びます。

では、プログラムにおける関数はどうでしょうか?プログラムにおける入力・出力は、なにも数値とは限りません。数値や文字列、それらを複数含むデータなど、ありとあらゆるデータが入力・出力になりえます。また、プログラムにおける関数の中には、今ではめったにこの名前を使う言語はないのですが、Pascalなどの古い言語では「プロシージャ」または「手続き」と呼ばれることもあり、これは特に出力(プログラミングではこれを戻り値または返り値と呼ぶ)を返さない関数のことを指します。このプロシージャは変換器というよりも処理の羅列という側面が強く、「関数」と呼ばない言語が存在するのもうなずけるところでしょう。

 ざっと関数の意味と歴史について触れたところで、関数型プログラミングの話に移ることにしましょう。現在、世の中で広く使われているプログラミング言語のおよそ99%(数字自体は適当ですが(^^;; )はC言語を先祖とする手続き型言語、またはオブジェクト指向言語と呼ばれるものです。
「名は体を表す」とはよく言ったもので、手続き型言語は主に手続きの羅列で実行する処理を表します。言ってみれば手続き型言語は、赤子に歩き方を手取り足取り教えるように、コンピュータにある問題を解決するための手順をひとつひとつ教えることで、プログラムを記述します。
オブジェクト指向言語は、これの単純な拡張に過ぎず、あるデータがあったらそれに対して施すべき処理(手続き)はそのデータに紐づくものなのだから、ひとまとめにして考えるようにすればわかりやすいよねという思想に基づき生まれたものでしかありません。このような構造をこれらの言語では、「クラス」と呼びますが、この記事の本題とは関係無いため、割愛します。
手続き型言語は部品も含めて自分で一からつくり上げるという印象が強い一方で、今回の本題に関連する関数型言語はどちらかと言えば、ブロックを積み重ねて問題解決の手順を示します。したがって、関数型言語の問題解決手順は、自由度が幾分低い代わりにその機能が類推しやすく、把握しやすいといえます。
もちろん、何にでも例外はつきものなので、手続き型・オブジェクト指向言語でもいろんなブロックがあらかじめ用意されている言語や、一般に関数型言語と言われていても、手続き型言語的側面を持つものもあります。


後編ではC#によるサンプルコードを交えつつ、実践的な関数型プログラミングスタイルの解説をしていきます。

2013年8月29日木曜日

マルチリンガルで行こう(WPF編)

えー、前回いつ更新したか覚えてないくらいにはご無沙汰してます、はざまです。
今回は、趣味グラミングアプリを作っていてちょっとはまった部分を自分用メモも兼ねてエントリーにしておこうと思います。題材にするのはその名も、WPFLocalizationExtensionです。このライブラリ、名前の通りWPFで作成するアプリのローカライゼーションを容易にしてくれます。具体的にどんなことができるのかは公式サイトのイントロダクション動画を参照していただくとして、残念ながらこのライブラリーはドキュメンテーションの質がイマイチなので、ここでは準備方法と使用方法の解説をしたいと思います。

まず、インストール方法ですが、nuGetが使えるならそこから入手するのが一番楽です。というか、その方法しか試したことはありません。一からビルドする場合には、ご自身でその方法を調査してみてください。
インストールが終わったら、まずサンプルとして以下のような.xamlファイルを作成します。

<Window
    x:Class="WPFLocalizationExtensionExample.ExampleView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:lex="http://wpflocalizeextension.codeplex.com"
    lex:LocalizeDictionary.DesignCulture="en"
    lex:ResxLocalizationProvider.DefaultAssembly="WPFLocalizationExtension"
    lex:ResxLocalizationProvider.DefaultDictionary="StringResources">
    <Grid>
        <TextBlock Text="{lex:Loc ExampleTexts_HelloWorld}" />
    </Grid>
</Window>

上記のコードに関していくつか補足しておきます。まず5行目の式は見た目通り、WPFLocalizationExtensionの名前空間をlexという名前でXAMLに取り込むことを指定しています。なぜlexなのかは、公式サイトなどでそう推奨されているからとしか答えようがありません。
次の6~8行の式はこのXAMLファイル全体に影響するWPFLocalizationExtensionの設定です。具体的に上から"VSなどのデザイナーで表示する言語設定","WPFLocalizationExtensionがリソースを検索する際に使用するアセンブリー名","WPFLocalizationExtensionがリソースを検索する際に使用する.resxファイルの名前"となっています。これらの式はXAMLファイル中のいずれの場所にも記述できて逐次、設定を変更できるようです。
なお、ここに記すメモはRESXファイルをリソースとして使用することを前提としています。WPFLocalizationExtensionの機能として適切なILocalizationProviderを用意すれば、.csvや.xml、はたまた.txt,.jsonファイルなどもリソースファイルとして使用できるようですが、話が煩雑になるためここでは一切触れません。
さて、XAMLファイルを用意したら次は、リソースを作成します。公式サイトの説明によると、RESXファイルはVSで新規プロジェクトを作成した際にプロジェクト直下に作られるPropertiesという名前のフォルダーになければならないらしいので、その場所に今回はStringResources.resxという名前でRESXファイルを作成します。そして、このファイルに次のエントリーを追加します。
名前(key):ExampleTexts_HelloWorld
値(value):Hello world!
さらにそのリソースファイルを開いたままVS2012の場合は、ファイルタブの直下を見てください。
上の画像で示されたアクセス修飾子というプルダウンリストから"Public"を指定してください。これがないとライブラリーがリソースにアクセスできなくなってしまうようです。
ここまで作業が終わったら先ほどのXAMLファイルのデザイナータブを開いてみてください。全て正常に動作していれば、Hello world!という文字列を表示するウインドウがデザイナー画面に表示されるはずです。これでひとまず、WPFLocalizationExtensionから文字列リソースを扱う準備は整いました。ここからがいよいよ本領発揮となる多言語への対応です。ここでは日本語リソースを追加してみましょう。
まず、Propertiesフォルダー内にStringResources.ja.resxというファイルを作成します。そして、次のエントリーを追加してください。
名前(key):ExampleTexts_HelloWorld
値(value):こんにちは、世界!
エントリーを追加したら一旦IDEを終了し、適当なテキストエディターでIDEで開いていたプロジェクトファイルを開いてください。すると、そこに以下のような要素があるはずです。

<EmbeddedResource Include="Properties\StringResources.ja.resx">

この要素の中身を次のように書き換えてください。
<SubType>Designer</SubType>
<DependentUpon>StringResources.resx</DependentUpon>

書き換えが終わったらしっかり保存してIDEに戻りましょう。この状態でデザイナー画面を開き、XAMLファイル内のlex:LocalizeDictionary.DesignCultureの値をjaにすれば、晴れてウインドウ内に表示されるテキストが日本語化されるはずです。
これでWPFアプリケーションのグローバリゼーションは完了です。あとは、他の言語のRESXファイルを追加するなり、文字列以外のリソースを追加するなり色々試してみてください。WPFLocalizationExtensionは汎用性が高い分、使用方法が幾分煩雑になっていますが、適切な前準備さえ終えてしまえばコードに"WPFLocalizeExtension.Engine.LocalizeDictionary.Instance.Culture = 使用したい言語を表すSystem.Globalization.CultureInfoオブジェクト"の一文を追加するだけで表示する言語が変わるなど非常に使い勝手のいいライブラリーだと思います。



最後に、タイトルの(WPF編)という一言について補足します。WPF編と銘打っているからには今後、シリーズ化して他のプラットフォームでのグローバリゼーションの話題も出すんだろうなと突っ込まれても困ります。シリーズ化するかは未定です。