v8是google开发的一个js引擎,其性能非常出色,包括Chrome在内的开源产品都在使用它,同时我们知道Chrome采用的是多进程模式,本文主要是例举一个基于v8的多进程JS编程API。
#include <vector>
#include "v8.h"
//读取js文件,返回js文件源码
v8::Handle<v8::String> ReadFile(const char* name)
{
FILE* file = fopen(name, "rb");
if (file == NULL) return v8::Handle<v8::String>();
fseek(file, 0, SEEK_END);
int size = ftell(file);
rewind(file);
char* chars = new char[size + 1];
chars[size] = '\0';
for (int i = 0; i < size;)
{
int read = fread(&chars[i], 1, size - i, file);
i += read;
}
fclose(file);
v8::Handle<v8::String> result = v8::String::New(chars, size);
delete[] chars;
return result;
}
//执行js源代码,其中有编译和运行两个小步骤,并直接打印结果
void ExecuteString(const v8::Handle<v8::String> &source)
{
v8::HandleScope handle_scope;
v8::Handle<v8::Script> script = v8::Script::Compile(source);
v8::Handle<v8::Value> result = script->Run();
v8::String::Utf8Value str(result);
printf("%s\n", *str);
}
//
//线程模块,分为初始化和运行两个步骤
class Th : public v8::internal::Thread
{
public:
Th(const char * js_func_name) : Thread("nameless")
{
strcpy(_fname,js_func_name);
}
virtual void Run()
{
Execute4Thread();
}
private:
void Execute4Thread()
{
v8::Isolate* isolate = v8::Isolate::New();
v8::Isolate::Scope iscope(isolate);
v8::HandleScope scope;
v8::Persistent<v8::Context> context = v8::Context::New();
v8::Context::Scope cscope(context);
run_proc();
context.Dispose();
}
void run_proc()
{
ExecuteString(ReadFile(_fname));
}
char _fname[20];
};
/////
// 这个用于从js的参数中获取参数所属的c++对象,并返回对象指针
template<class T>
T* get_cppobj_ptr(v8::Handle<v8::Object> obj)
{
v8::Handle<v8::External> field = v8::Handle<v8::External>::Cast(obj->GetInternalField(0)) ;
void* raw_obj_ptr = field->Value() ;
return static_cast<T*>(raw_obj_ptr);
};
//暴露给js的c++对象,用于创建和运行线程
class Worker
{
public:
static v8::Handle<v8::Value> Start(const v8::Arguments & args)
{
Worker * worker_ptr = get_cppobj_ptr<Worker>(args.Holder()) ;
worker_ptr->StartWorker(args);
}
static v8::Handle<v8::Value> Join(const v8::Arguments & args)
{
Worker * worker_ptr = get_cppobj_ptr<Worker>(args.Holder()) ;
worker_ptr->JoinWorker(args);
}
inline void StartWorker(const v8::Arguments & args)
{
for (int i = 0; i < args.Length(); i++)
{
v8::String::Utf8Value str(args[i]);
Th *th = new Th(*str);
th->Start();
ths_.push_back(th);
}
}
inline void JoinWorker(const v8::Arguments & args)
{
std::vector<Th*>::iterator it = ths_.begin();
for (; it!=ths_.end(); ++it)
{
(*it)->Join();
}
}
private:
std::vector<Th*> ths_;
};
//注册相关的c++对象到js环境中
void creat_obj(v8::Persistent<v8::Context> &exec_context)
{
v8::Handle<v8::ObjectTemplate> foo_templ ;
v8::Handle<v8::Object> foo_class_obj ;
v8::Handle<v8::External> foo_class_ptr ;
Worker * g_foo_ptr = new Worker;
foo_templ = v8::ObjectTemplate::New();
foo_templ->SetInternalFieldCount(1);
foo_class_obj = foo_templ->NewInstance();
foo_class_ptr = v8::External::New(static_cast<Worker *>(g_foo_ptr)) ;
foo_class_obj->SetInternalField(0, foo_class_ptr) ;
foo_class_obj->Set(v8::String::New("Start"),
v8::FunctionTemplate::New(Worker::Start)->GetFunction()) ;
foo_class_obj->Set(v8::String::New("Join"),
v8::FunctionTemplate::New(Worker::Join)->GetFunction()) ;
exec_context->Global()->Set(v8::String::New("Worker"),
foo_class_obj,
(v8::PropertyAttribute)(v8::ReadOnly)) ;
}
int main()
{
v8::HandleScope handle_scope;
v8::Persistent<v8::Context> exec_context = v8::Context::New();
v8::Context::Scope context_scope(exec_context);
creat_obj(exec_context);
ExecuteString(ReadFile("test.js"));
return 0;
}
假设我们有三个js脚本文件:
// test.js
Worker.Start('test1.js');
Worker.Start('test2.js');
Worker.Join();
'ok';
// test1.js
var str = 'test1';
for(i=0;i<=10000;i++)
str;
// test2.js
var str = 'test2';
str;
这边使用的是linux环境下,v8默认使用pthread库,通过静态编译以上的c++程序,
[root@hx test]# g++ -o test test.cpp libv8.a -I/var/www/cpp/v8/src -lpthread -fno-rtti -fno-exceptions
[root@hx test]# ./test
test2
test1
ok
我们可以看到由于test1的运行时间比较长,故而后输出结果。