Skip to content

Instantly share code, notes, and snippets.

@acidlemon
Last active Aug 29, 2015
Embed
What would you like to do?
embedded Perl in Go /w goroutine
package main
/*
#include <EXTERN.h>
#include <perl.h>
#include <stdio.h>
void init_perl() {
// PerlのCランタイムの初期化(全体で1回)
int argc = 0;
char** argv = NULL;
char** env = NULL;
PERL_SYS_INIT3(&argc, &argv, &env);
}
PerlInterpreter* prepare_perl() {
PerlInterpreter* perl;
// Perlインタプリタの初期化
perl = perl_alloc();
PERL_SET_CONTEXT(perl);
perl_construct(perl);
// Perlインタプリタの実行
char empty[16] = "", e[16] = "-e", zero[16] = "0";
char *embedding[] = { empty, e, zero };
perl_parse(perl, NULL, 3, embedding, NULL);
perl->Iexit_flags |= PERL_EXIT_DESTRUCT_END;
perl_run(perl);
return perl;
}
void release_perl(PerlInterpreter* perl) {
perl_destruct(perl);
perl_free(perl);
}
void term_perl() {
PERL_SYS_TERM();
}
SV* Perl_eval_pv(PerlInterpreter*, const char*, int);
// SvIVはマクロでGoから直接使えないのでC関数にする
long Sv2Iv(PerlInterpreter* perl, SV* sv) {
return Perl_sv_2iv_flags(perl, sv, SV_GMAGIC);
}
*/
import "C"
import "fmt"
import "sync"
func main() {
C.init_perl() // Perlの準備
wg := sync.WaitGroup{}
test_func := func(val int) {
defer wg.Done() // 関数抜けたら待ってるやつに終了を通知
perl := C.prepare_perl() // インタプリタ作成
defer C.release_perl(perl) // 関数抜けたらインタプリタを破棄
// Perlの文を評価してスカラ値を取得
sv := C.Perl_eval_pv(perl, C.CString(fmt.Sprintf("my $powawa = %d; $powawa **= 2", val)), 1)
fmt.Printf("powawa = %v\n", C.Sv2Iv(perl, sv))
}
// 10並列で実行
limit := 10
for i := 0; i < limit; i++ {
wg.Add(1)
go test_func(i)
}
wg.Wait()
C.term_perl() // Perlの後始末
}
@acidlemon
Copy link
Author

acidlemon commented Nov 28, 2014

$ CGO_CFLAGS=`perl -MExtUtils::Embed -e ccopts` \
  CGO_LDFLAGS=`perl -MExtUtils::Embed -e ldopts` \
  go run parallel.go

で実行すると

powawa = 81
powawa = 4
powawa = 9
powawa = 25
powawa = 64
powawa = 49
powawa = 1
powawa = 0
powawa = 16
powawa = 36

という結果が得られます(並列実行なので結果は毎回順番が変わります)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment