1. 먼저 작성하세요
인터넷의 급속한 발전과 램프 아키텍처의 인기로 인해 PHP는 점점 더 많은 확장 기능을 지원하며 이는 PHP 개발을 직접적으로 촉진합니다.
그러나 PHP 역시 스크립팅 언어에서는 피할 수 없는 문제가 있습니다. C 등의 컴파일 언어와는 성능이 많이 다르기 때문에 성능 문제를 고려할 때는 PHP 확장을 통해 해결하는 것이 가장 좋습니다.
그럼, PHP 확장을 만드는 방법은 다음과 같습니다. 예제부터 시작해 보겠습니다(이 문서에는 C 기본 사항이 필요합니다).
2. 문제 해결
시스템에서 배열의 제곱합이 자주 필요한 경우 다음과 같이 작성할 수 있습니다.
- 함수 array_square_sum($data){
- $sum = 0;
- foreach($data를 $value로){
- $sum = $value * $value;
- }
- return $sum;
- }
실제 실행 시 코드 복사 , PHP Zend 엔진은 이 구절을 C 언어로 번역하며, 매번 메모리 할당이 필요합니다. 그래서 성능이 상대적으로 안좋습니다. 또한 성능 고려 사항을 기반으로 이를 수행하기 위한 확장을 작성할 수 있습니다.
3. 확장 프로그램 작성
확장 프로그램을 빌드하려면 최소 2개의 파일이 필요합니다. 하나는 이 확장을 컴파일하는 데 필요한 최소한 종속 라이브러리를 컴파일러에 알려주는 구성 파일입니다. 두 번째는 실제 실행 파일입니다.
3.1 프레임워크 생성
복잡해 보이지만 실제로는 확장된 프레임워크를 얻는 데 도움이 되는 도구가 있습니다. PHP 소스 코드에는 확장 프레임워크를 생성하는 데 도움이 되는 ext_skel 도구가 있습니다. - liujun@ubuntu:~/test/php-5.5.8/ext$ ls ext_skel
- ext_skel
코드 복사
이제 이를 사용하여 확장된 array_square_sum을 생성합니다. ($는 프롬프트 명령을 나타냅니다) - $ ./ext_skel --extname=array_square_sum
- array_square_sum 디렉토리 생성
- 기본 파일 생성: config.m4 config.w32 . svnignore array_square_sum.c php_array_square_sum.h 크레딧 실험 테스트/001.phpt array_square_sum.php [done].
- 새 확장 기능을 사용하려면 다음 단계를 실행해야 합니다:
- 1 . $ cd ..
- 2. $ vi ext/array_square_sum/config.m4
- 3. $ ./buildconf
- 4. $ ./configure --[with|enable]-array_square_sum
- 5 . $ make
- 6. $ ./php -f ext/array_square_sum/array_square_sum.php
- 7. $ vi ext/array_square_sum/array_square_sum.c
- 8. 3단계를 반복하세요. -6 ext/array_square_sum/config.m4에 만족할 때까지
- 6단계에서 모듈이 PHP로 컴파일되었는지 확인한 다음
- 코드 작성을 시작하고 필요한 만큼 마지막 두 단계를 반복하세요.
코드 복사 명령을 실행한 후 터미널에서는 새로운 확장 프로그램을 생성하는 방법을 알려줍니다. 파일 내용을 확인하면 config.m4, php_array_square_sum.h, array_square_sum.c와 같은 몇 가지 중요한 파일이 있다는 것을 알 수 있습니다. 이에 대해서는 아래에서 하나씩 설명하겠습니다. liujun@ubuntu:~/test/php-5.5.8/ext$ ll array_square_sum/ 총 44- drwxr-xr-x 3 liujun liujun 4096 1월 29일 15:40 ./
- drwxr-xr-x 80 liujun liujun 4096 1월 29일 15:40 ../
- -rw-r--r-- 1 liujun liujun 5548 1월 29일 15:40 array_square_sum .c
- -rw-r--r-- 1 liujun liujun 532 1월 29일 15:40 array_square_sum.php
- -rw-r--r-- 1 liujun liujun 2354 1월 29일 15:40 config.m4
- -rw-r--r-- 1 liujun liujun 366 1월 29일 15:40 config.w32
- -rw-r--r-- 1 liujun liujun 1월 29일 15:40 크레딧
- - rw-r--r-- 1 liujun liujun 0 1월 29일 15:40 실험
- -rw-r--r-- 1 liujun liujun 3112 1월 29일 15:40 php_array_square_sum.h
- -rw-r- -r-- 1 liujun liujun 1월 16일 15:40 .svnignore
- drwxr-xr-x 2 liujun liujun 4096 1월 29일 15:40 테스트/
코드 복사
3.2 구성 파일 config.m4 dnl PHP_ARG_WITH(array_square_sum, array_square_sum 지원용, dnl 주석이 정렬되었는지 확인하세요.- dnl [ --with-array_square_sum array_square_sum 지원 포함])
코드 복사
dnl 제거 PHP_ARG_WITH(array_square_sum, array_square_sum 지원의 경우, 주석이 정렬되었는지 확인하세요.- [ --with-array_square_sum array_square_sum 포함 지원])
코드 복사 이는 ./configure 시 활성화 샘플 옵션을 호출할 수 있는 최소 요구 사항입니다. ./configure 처리 중에 이 확장 구성 파일에 도달하면 PHP_ARG_ENABLE의 두 번째 매개 변수가 표시됩니다. 최종 사용자에 의해 ./configure --help 실행 시 도움말 정보로 표시됩니다.
3.3 헤더 파일
php_array_square_sum.h를 수정하고,confirm_array_square_sum_compiled를 verify_array_square_sum으로 변경합니다. 이는 앞으로 우리가 실제로 호출할 함수의 이름입니다. 물론, verify_array_square_sum_compiled를 삭제하지 않고, verify_array_square_sum 함수를 직접 추가할 수도 있습니다. - PHP_FUNCTION(confirm_array_square_sum_compiled);
코드 복사 해야 합니다 - PHP_FUNCTION(array_square_sum);
코드 복사
3.3 소스코드
array_square_sum.c를 수정하고 verify_array_square_sum_compiled를 verify_array_square_sum으로 변경합니다. 이 확장자를 등록하는 함수입니다. 3.2에서confirm_array_square_sum을 직접 추가했다면 이 단계에서 직접 verify_array_square_sum을 추가하면 됩니다. - const zend_function_entry array_square_sum_functions[] = {
- PHP_FE(confirm_array_square_sum_compiled, NULL) /* 테스트를 위해 나중에 제거하세요. */
- PHP_FE_END /* array_square_sum_functions[] */
- };
코드를 복사하여 로 변경하세요. - const zend_function_entry array_square_sum_functions[] = {
- PHP_FE(array_square_sum, NULL) /* 테스트를 위해 나중에 제거하세요. */
- PHP_FE_END /* array_square_sum_functions[]의 마지막 줄이어야 합니다. */
- } ;
코드 복사
그러면 가장 중요한 단계는 verify_array_square_sum을 다시 작성하는 것입니다. 이때, verify_array_square_sum_compiled를 verify_array_square_sum으로 다시 작성하기만 하면 됩니다(confirm_array_square_sum_compiled는 3.1에서는 삭제되지 않았으므로 verify_array_square_sum을 추가해야 합니다). - PHP_FUNCTION(confirm_array_square_sum_compiled)
코드 복사
- PHP_FUNCTION(array_square_sum)
- {
- zval* array_data;
- HashTable *ht_data;
- int ret;< 🎜으로 다시 작성됨 > char* key;
- 단위 인덱스;
- zval **pdata;
- double sum = 0;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array_data) = = 실패) {
- return;
- }
- ht_data = Z_ARRVAL_P(array_data);
- zend_hash_internal_pointer_reset(ht_data);
- while ( HASH_KEY_NON_EXISTANT != (ret = zend_hash_get_current_key(ht_ data,&key) , &index, 0)) ) {
- ret = zend_hash_get_current_data(ht_data, &pdata);
-
- if( Z_TYPE_P(*pdata) == IS_LONG){
- sum = Z_LVAL_P(*pdata) * Z_LVAL_P (*pdata);
- }else {
- RETURN_FALSE;
- }
- zend_hash_move_forward(ht_data);
- }
- zend_hash_internal_pointer_end(Z_ARRVAL_P(array_data));
- RETVAL_DOUBLE(sum) ;
- }
코드 복사
PHP는 약한 유형의 언어이며 해당 데이터는 zval 구조에 저장됩니다. . typedef Union _zval { long lval; double dval; struct { char *val;- int len;
- } str;
- HashTable *ht;
- zend_object_value obj;
- } zval;
- 코드 복사
함수가 전달한 매개변수를 얻으려면 zend_parse_parameters() API 함수를 사용할 수 있습니다. 다음은 함수의 프로토타입입니다. zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, …); 코드 복사 -
커널의 매크로를 사용하여 zend_parse_parameters() 함수의 처음 몇 개의 매개변수를 직접 생성할 수 있습니다. 형식은 ZEND_NUM_ARGS() TSRMLS_CC입니다. 쉼표가 없습니다. 이름에서 알 수 있듯이 ZEND_NUM_ARGS()는 매개변수의 개수를 나타냅니다. 그 뒤에는 공통 매개변수 유형(C 언어의 printf와 유사)과 공통 매개변수 목록이 옵니다.
다음 표에는 일반적인 매개변수 유형이 나열되어 있습니다.
参数类型 |
对象C类型 |
说明 |
l |
long |
整数 |
b |
bool |
布尔 |
s |
char* |
字符串 |
d |
double |
浮点数 |
a |
array(zval*) |
数组 |
z |
zval* |
不确定性zval |
또한 배열은 대규모 해시 테이블로 구현되므로 zend_hash_get_current_key는 배열을 탐색하고 매크로 Z_LVAL_P(zval*)를 사용하여 실제 값을 얻을 수 있습니다. 마지막으로 결과를 합산할 수 있습니다. RETVAL_DOUBLE(값)도 매크로입니다. 반환 결과는 double이고 값은 value입니다. 자세한 내용은 "php 확장 개발.pdf"를 참조하세요.
드디어 본 기능의 개발이 완료되었습니다.
3.4 구성 파일 생성
그런 다음 ~/php/bin/phpize를 실행합니다
/home/liujun/php/bin/phpize 코드 복사 구성 대상:- PHP Api 버전: 20121113
- Zend 모듈 Api 번호: 20121212
- Zend Extension Api 번호: 220121212
코드 복사
array_square_sum에 실행 가능한 스크립트 구성이 나타나는 것을 확인할 수 있습니다.
3.5편찬
시스템 기본 php-config-path가 현재 사용 중인 php 경로가 아닐 수 있으므로 컴파일할 때 php-config PATH를 가져오는 것이 가장 좋습니다. liujun@ubuntu:~/test/php-5.5.8/ext/array_square_sum$ ./configure --with-php-config=/home/liujun/php /bin/php-config 코드 복사 컴파일이 성공하면 터미널에 다음 프롬프트가 표시됩니다: libtool 생성- libtool에 "CXX" 구성 태그 추가
- configure: ./config.status 생성
- config.status: config.h 생성
- config.status: config.h 변경되지 않았습니다
코드 복사 array_square_sum 디렉토리의 모듈 디렉토리를 확인하면 array_square_sum.so가 생성된 것을 확인할 수 있습니다. 이것이 우리에게 필요한 확장입니다. . liujun@ubuntu:~/test/php-5.5.8/ext/array_square_sum$ ls module/- array_square_sum.la array_square_sum.so
코드 복사
4. 확장 프로그램 사용
4.1. 구성 확장
php 구성 php.ini를 수정하고 구성 내용을 추가합니다. [array_square_sum]- extension=array_square_sum.so
코드 복사
4.2.모듈 추가
PHP 확장은 일반적으로 $PHP_PATH/lib/php/extensions/no-debug-non-zts-yyyymmdd에 있습니다. 찾을 수 없으면 Baidu 또는 Google에 .so 파일이 많이 있습니다. .
3.5에서 생성된 array_sum_square.so를 복사하면 됩니다.
fastcgi 모드를 사용하는 경우 PHP를 다시 시작해야 하므로 PHP 확장자는 array_square_sum이어야 합니다. 자세한 내용은 phpinfo를 확인하세요. 알아요)
4.2 코드 작성
Extension을 작성하면 운영 효율성이 향상될 수 있으므로 여기서는 Extension을 사용하고 PHP 코드를 직접 사용하여 성능을 비교하고 테스트합니다. 여러 번 실험하면 오류를 줄일 수 있으므로 2,000번을 반복하여 100,000개의 숫자의 제곱의 합을 구하세요. 코드는 다음과 같습니다: $data = array();- $max_index = 100000;
- $test_time = 2000 ;
- for($i=0; $i<$max_index; $i ){
- $data[] = $i
- }
- $php_test_time_start = time();
- php_test ($test_time, $data);
- $php_test_time_stop = time();
- echo "php 테스트 연장 시간은 "입니다. ($php_test_time_stop - $php_test_time_start);
- $c_test_time_start = time();
- c_test($test_time, $data);
- $c_test_time_stop = time();
- echo "php 테스트 시간은 "입니다. ($c_test_time_stop - $c_test_time_start)" n";
-
- 함수 php_test($test_time, $test_data){
- for($i=0; $i<$test_time; $i ){
- $sum = 0;
- foreach($ test_data as $data){
- $sum = $data * $data;
- }
- }
- }
-
- 함수 c_test($test_time, $test_data){
- for ($i=0; $i<$test_time; $i ){
- $sum = array_square_sum($test_data);
- }
- }
코드 복사 테스트 결과는 다음과 같습니다. liujun@ubuntu:~/php$ ~/php/bin/php test.php - php 테스트 시간은 30
- php 테스트 시간은 2
코드 복사 확장 프로그램이 PHP를 직접 사용하는 것보다 15배 빠른 것을 확인할 수 있습니다. 비즈니스 로직이 더욱 복잡해짐에 따라 이러한 차별화는 더욱 커질 것입니다.
그런 다음 C 언어를 사용하여 직접 수행합니다. 다음은 테스트할 코드입니다(테스트 조건은 정확히 동일합니다). - #include
- #include
- #include
-
- #define TEST_TIME 2000
- #define MAX_INDEX 100000
-
- int main()
- {
- int data[MAX_INDEX];
- 이중 합계 = 0;
-
- for(int i=0; i data[i] = i;
- }
-
- 구조체 timeval start ;
- struct timeval end;
-
- gettimeofday(&start,NULL);
-
- for(int i=0; i for(int j= 0 ; j sum = data[j] * data[j];
- }
- }
- gettimeofday(&end,NULL);
-
- 두 배 = (end.tv_sec-start.tv_sec) (end.tv_usec-start.tv_usec) * 1.0 /1000000;
- printf("총 시간은 %lfn", time );
- printf("총 시간은 %입니다. lfn ", sum);
- return 0;
- }
코드 복사
실행해서 효과를 확인해보면 C를 직접 사용한 시간은 0.261746에 불과해 C 확장을 사용한 경우의 13.09%, PHP를 직접 사용한 경우의 0.87%에 불과한 것을 알 수 있다. 물론 IO와 같은 복잡한 작업이 포함된 경우 C/C는 PHP보다 수만 배 빠릅니다(테스트됨).
- liujun@ubuntu:~/php$ g test.cpp -O2 -o test
- liujun@ubuntu:~/ php$ ./test
- 총 시간은 0.261746
- 합계 시간은 36207007178615872.000000
코드 복사
따라서 인덱싱, 단어 분할 등 매우 높은 성능이 요구되는 실제 서비스에서는 C를 사용하여 기본 서비스 세트를 만들고 PHP를 사용하여 캡슐화할 수 있습니다. 전화.
|