September 2008 Archives
펄매니아 게시판에서 변수 치환과 관련되어.. 라는 글을 보니 다음과 같은 질문이 있었다.
만약 다음과 같은 문자열들이 있다면
my $sql = 'select $col from table';
my $col = 'mycolumn';
$sql에서 문자열 치환으로 $col의 변수 값을 넣어 "select mycolumn from table" 처럼 만들고 싶다는 것이었는데, 일단 답은
$sql =~ s/(\$\S+)/eval($1)/ge;
였다. Perl 정규식에서 e modifier는 치환될 부분을 명령으로 실행해주는데 정규식을 뜯어 보자면 $로 시작하고 공백이 아닌 것 까지를 그루핑(grouping)해서 그 매치값이 담긴 $1(여기서는 $col)을 포함한 eval($1) 이란 문자열로 만들어서 정규식의 e modifier로 그 문자열을 하나의 Perl 코드로 실행하는 것이다. 따라서 대치될 문자열은 eval($1)의 실행 결과가(mycolumn)되어 치환 정규식이 끝난 후 $sql 문자열은 "select mycolumn from table"이 된다.
여기서
$sql =~ s/(\$\S+)/eval($1)/ge;
는 안쪽의 eval을 빼내서 e modifier 하나를 더 주는 형식
$sql =~ s/(\$\S+)/$1/gee;
로 만들 수 있다. 이런 것을 multiple e modifier라고 하는데 두 개 이상 여러 개 쓸 수도 있다. 다음 코드를 보면 여러개의 e modifier들이 어떻게 동작하는지 알 수 있을 것이다. ( e 두 개 까지는 어떤 전형적인 테크닉으로 종종 사용하지만, 그 이상의 e를 남발하는 건 코드골프 같은 것을 할 때 말고 실용적 코드에서는 쓸 일 도 없고 쓰는 걸 보지도 못했다.)
<코드>
#!/usr/bin/perl
use strict;
use warnings;
my $sql = 'select $col from table';
my $col = '$col2';
my $col2 = '$col3';
my $col3 = 'column';
my $temp;
$temp=$sql;
$temp =~ s/(\$\S+)/eval $1/ge;
print "$temp\n";
$temp=$sql;
$temp =~ s/(\$\S+)/$1/gee;
print "$temp\n\n";
$temp=$sql;
$temp =~ s/(\$\S+)/eval eval $1/ge;
print "$temp\n";
$temp=$sql;
$temp =~ s/(\$\S+)/$1/geee;
print "$temp\n\n";
$temp=$sql;
$temp =~ s/(\$\S+)/eval eval eval $1/ge;
print "$temp\n";
$temp=$sql;
$temp =~ s/(\$\S+)/$1/geeee;
print "$temp\n\n";
<결과>
select $col2 from table
select $col2 from table
select $col3 from table
select $col3 from table
select column from table
select column from table
만약 다음과 같은 문자열들이 있다면
my $sql = 'select $col from table';
my $col = 'mycolumn';
$sql에서 문자열 치환으로 $col의 변수 값을 넣어 "select mycolumn from table" 처럼 만들고 싶다는 것이었는데, 일단 답은
$sql =~ s/(\$\S+)/eval($1)/ge;
였다. Perl 정규식에서 e modifier는 치환될 부분을 명령으로 실행해주는데 정규식을 뜯어 보자면 $로 시작하고 공백이 아닌 것 까지를 그루핑(grouping)해서 그 매치값이 담긴 $1(여기서는 $col)을 포함한 eval($1) 이란 문자열로 만들어서 정규식의 e modifier로 그 문자열을 하나의 Perl 코드로 실행하는 것이다. 따라서 대치될 문자열은 eval($1)의 실행 결과가(mycolumn)되어 치환 정규식이 끝난 후 $sql 문자열은 "select mycolumn from table"이 된다.
여기서
$sql =~ s/(\$\S+)/eval($1)/ge;
는 안쪽의 eval을 빼내서 e modifier 하나를 더 주는 형식
$sql =~ s/(\$\S+)/$1/gee;
로 만들 수 있다. 이런 것을 multiple e modifier라고 하는데 두 개 이상 여러 개 쓸 수도 있다. 다음 코드를 보면 여러개의 e modifier들이 어떻게 동작하는지 알 수 있을 것이다. ( e 두 개 까지는 어떤 전형적인 테크닉으로 종종 사용하지만, 그 이상의 e를 남발하는 건 코드골프 같은 것을 할 때 말고 실용적 코드에서는 쓸 일 도 없고 쓰는 걸 보지도 못했다.)
<코드>
#!/usr/bin/perl
use strict;
use warnings;
my $sql = 'select $col from table';
my $col = '$col2';
my $col2 = '$col3';
my $col3 = 'column';
my $temp;
$temp=$sql;
$temp =~ s/(\$\S+)/eval $1/ge;
print "$temp\n";
$temp=$sql;
$temp =~ s/(\$\S+)/$1/gee;
print "$temp\n\n";
$temp=$sql;
$temp =~ s/(\$\S+)/eval eval $1/ge;
print "$temp\n";
$temp=$sql;
$temp =~ s/(\$\S+)/$1/geee;
print "$temp\n\n";
$temp=$sql;
$temp =~ s/(\$\S+)/eval eval eval $1/ge;
print "$temp\n";
$temp=$sql;
$temp =~ s/(\$\S+)/$1/geeee;
print "$temp\n\n";
<결과>
select $col2 from table
select $col2 from table
select $col3 from table
select $col3 from table
select column from table
select column from table
각종 언어들의 Thread Model이 잘 설명된 글:A Threading Model Overview 에서 발췌
Perl
Perl has an interesting threading model, one which Mozilla borrowed for SpiderMonkey if I'm not mistaken. Instead of having a global interpreter lock like Python, Perl makes all global state thread local and spawns off a new interpreter with each new thread. This allows for true native threading. There are two catches though.
First, you must explicitly make variables available to threads outside your own. This is the nature of everything being thread local. The values must then be kept up to date across threads.
The second catch is that every new thread is very expensive to create. The interpreter is not small, and duplicating it with every thread makes for a lot of overhead.
요약하면 Perl thread model은 독특한데( Python, Ruby의 thread 구현은 현재 다각적으로 개선이 이루어지고 있지만 현 상태로는 멀티프로세서 환경에서 잇점을 얻기가 힘들다고 함 ) Mozilla의 SpiderMonkey도 이 모델을 빌렸으며 Perl의 새로운 각 thread는 새로운 해석기를 생성하며 global state를 thread local화하기 때문에 실제 native threading을 쓸 수 있게 한다.
이런 구조에서 조심해야하는 것은 thread local화 때문에 공유할 변수들은 모든 thread에서 최신의 상태에 접근 가능하도록 명시적으로 지정(thread::shared 모듈)을 해줘야 하며 thread 생성 시 thread별로 크기가 작지 않은 해석기를 독립적으로 가지기 때문에 그에 따른 오버헤드와 비용이다.
추가 참고문서: http://perldoc.perl.org/perlthrtut.html
Perl
Perl has an interesting threading model, one which Mozilla borrowed for SpiderMonkey if I'm not mistaken. Instead of having a global interpreter lock like Python, Perl makes all global state thread local and spawns off a new interpreter with each new thread. This allows for true native threading. There are two catches though.
First, you must explicitly make variables available to threads outside your own. This is the nature of everything being thread local. The values must then be kept up to date across threads.
The second catch is that every new thread is very expensive to create. The interpreter is not small, and duplicating it with every thread makes for a lot of overhead.
요약하면 Perl thread model은 독특한데( Python, Ruby의 thread 구현은 현재 다각적으로 개선이 이루어지고 있지만 현 상태로는 멀티프로세서 환경에서 잇점을 얻기가 힘들다고 함 ) Mozilla의 SpiderMonkey도 이 모델을 빌렸으며 Perl의 새로운 각 thread는 새로운 해석기를 생성하며 global state를 thread local화하기 때문에 실제 native threading을 쓸 수 있게 한다.
이런 구조에서 조심해야하는 것은 thread local화 때문에 공유할 변수들은 모든 thread에서 최신의 상태에 접근 가능하도록 명시적으로 지정(thread::shared 모듈)을 해줘야 하며 thread 생성 시 thread별로 크기가 작지 않은 해석기를 독립적으로 가지기 때문에 그에 따른 오버헤드와 비용이다.
추가 참고문서: http://perldoc.perl.org/perlthrtut.html

