Entries

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

NSOperationとC++

タグ: Objective-C C++ NSOperation Boost

NSOperationQueueは便利だが、都度スレッドを立ち上げていることを考えると、使用コストは決して低くはない。
実際どのくらいのものか、任意のC++関数を呼ぶNSOperation派生クラス(自分にとってこれが最も使いやすい)を使って計ってみる(ついでに派生クラス自体のコストも計る)。
実行環境は以下の通り。

  • MacBook Pro Core Duo 2.0 GHz
  • Mac OS X 10.5.5
  • XCode 3.1
  • Boost 1.36.0
#import <Foundation/Foundation.h>
#undef check
#include <boost/timer.hpp>
#include <boost/function.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

@interface CppInvocationOperation : NSOperation
{
	boost::function<void (NSOperation*)>* func;
}
- (id)initWithFunction:(const boost::function<void (NSOperation*)>&)f;
@end

@implementation CppInvocationOperation

- (id)initWithFunction:(const boost::function<void (NSOperation*)>&)f
{
	if(self = [super init])
	{
		func = new boost::function<void (NSOperation*)>(f);
	}
	return self;
}

- (void)dealloc
{
	delete func;
	[super dealloc];
}

- (void)main
{
	(*func)(self);
}

@end

int f(int n)
{
	return n * n;
}

void native(int count)
{
	int a[count];
	boost::timer t;	
	for(int i = 0; i < count; i++)
	{
		a[i] = f(i);
	}
	NSLog(@"native %fs", t.elapsed());
}

void lambda(int count)
{
	int a[count];
	boost::timer t;	
	for(int i = 0; i < count; i++)
	{
		using namespace boost::lambda;
		(var(a[i]) = bind(&f, i))();
	}
	NSLog(@"lambda %fs", t.elapsed());
}

void direct(int count)
{
	int a[count];
	boost::timer t;	
	for(int i = 0; i < count; i++)
	{
		using namespace boost::lambda;
		CppInvocationOperation* op =
			[[CppInvocationOperation alloc]
				initWithFunction:(var(a[i]) = bind(&f, i))
			];
		[op main];
		[op release];
	}
	NSLog(@"direct %fs", t.elapsed());	
}

void queue(int count)
{
	NSOperationQueue* queue = [[NSOperationQueue alloc] init];
	int a[count];
	boost::timer t;	
	for(int i = 0; i < count; i++)
	{
		using namespace boost::lambda;
		CppInvocationOperation* op =
			[[CppInvocationOperation alloc]
				initWithFunction:(var(a[i]) = bind(&f, i))
			];
		[queue addOperation:op];
		[op release];
	}
	[queue waitUntilAllOperationsAreFinished];
	NSLog(@"queue  %fs", t.elapsed());
	[queue release];
}

int main (int, const char*)
{
	NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
	
	const int count = 10000;

	native(count);
	lambda(count);
	direct(count);
	queue(count);
	
	[pool drain];
	
    return 0;
}

処理の内容は a[10000] の全要素に対し a[n] = f(n) を適用するというもの。
それを、NSOperationQueueを使って馬鹿正直にスレッドを分けて行う。
関数fは、ただ引数nを二乗して返す。
どう考えてもスレッドを立ち上げるコストの方が高い。

native 0.000044s 
lambda 0.000959s 
direct 0.044792s 
queue  0.946171s

CppInvocationOperationは楽だが、「関数オブジェクトを作ってnewしてコピーして」と、やはりそれなりにコストが掛かる。
まあ、NSOperationQueue自体のオーバーヘッドが1処理辺り0.1msあるので、このくらいのコストは埋もれてしまいそうだが……

スポンサーサイト

コメント

コメントの投稿

コメントの投稿
管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://idlysphere.blog66.fc2.com/tb.php/137-40d109c4
この記事にトラックバックする(FC2ブログユーザー)

Appendix

タグ

Blog内検索

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。