백엔드 개발 PHP 튜토리얼 PHP 커널 복호화 시리즈: zend_execute 실행 프로세스

PHP 커널 복호화 시리즈: zend_execute 실행 프로세스

Aug 08, 2016 am 09:22 AM
array data execute executor zend

PHP 커널 복호화 시리즈: zend_execute의 실행 과정

인터프리터 엔진이 최종적으로 op를 실행하는 함수는 zend_execute이다. zend_execute가 기본적으로 실행을 가리킬 때 이 실행은 {PHPSRC}/Zend/zend_vm_execute.h에 정의됩니다:
ZEND_API void execute(zend_op_array *op_array TSRMLS_DC) { zend_execute_data *execute_data; zend_bool nested = 0; zend_bool original_in_execution = EG(in_execution); if (EG(exception)) { return; } EG(in_execution) = 1; zend_vm_enter: /* Initialize execute_data */ execute_data = (zend_execute_data *)zend_vm_stack_alloc( ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval**) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2)) + ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * op_array->T TSRMLS_CC); EX(CVs) = (zval***)((char*)execute_data + ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data))); memset(EX(CVs), 0, sizeof(zval**) * op_array->last_var); EX(Ts) = (temp_variable *)(((char*)EX(CVs)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval**) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2))); EX(fbc) = NULL; EX(called_scope) = NULL; EX(object) = NULL; EX(old_error_reporting) = NULL; EX(op_array) = op_array; EX(symbol_table) = EG(active_symbol_table); EX(prev_execute_data) = EG(current_execute_data); EG(current_execute_data) = execute_data; EX(nested) = nested; nested = 1; if (op_array->start_op) { ZEND_VM_SET_OPCODE(op_array->start_op); } else { ZEND_VM_SET_OPCODE(op_array->opcodes); } if (op_array->this_var != -1 && EG(This)) { Z_ADDREF_P(EG(This)); /* For $this pointer */ if (!EG(active_symbol_table)) { EX(CVs)[op_array->this_var] = (zval**)EX(CVs) + (op_array->last_var + op_array->this_var); *EX(CVs)[op_array->this_var] = EG(This); } else { if (zend_hash_add(EG(active_symbol_table), "this", sizeof("this"), &EG(This), sizeof(zval *), (void**)&EX(CVs)[op_array->this_var])==FAILURE) { Z_DELREF_P(EG(This)); } } } EG(opline_ptr) = &EX(opline); EX(function_state).function = (zend_function *) op_array; EX(function_state).arguments = NULL; while (1) { int ret; #ifdef ZEND_WIN32 if (EG(timed_out)) { zend_timeout(0); } #endif if ((ret = EX(opline)->handler(execute_data TSRMLS_CC)) > 0) { switch (ret) { case 1: EG(in_execution) = original_in_execution; return; case 2: op_array = EG(active_op_array); goto zend_vm_enter; case 3: execute_data = EG(current_execute_data); default: break; } } } zend_error_noreturn(E_ERROR, "Arrived at end of main loop which shouldn't happen"); }
이 함수의 매개변수는 op_array이며, 이는 zend_op_array.op_array는 컴파일 과정에서 사용되며, zend_op_array 유형을 도입해야 합니다.
참조 소스: http://www.lai18.com/content/425167.html

zend_op_array 소개

이 유형은 {PHPSRC}/Zend/zend_compile.h에 정의되어 있습니다:
struct _zend_op_array { /* Common elements */ zend_uchar type; char *function_name; zend_class_entry *scope; zend_uint fn_flags; union _zend_function *prototype; zend_uint num_args; zend_uint required_num_args; zend_arg_info *arg_info; zend_bool pass_rest_by_reference; unsigned char return_reference; /* END of common elements */ zend_bool done_pass_two; zend_uint *refcount; zend_op *opcodes; zend_uint last, size; zend_compiled_variable *vars; int last_var, size_var; zend_uint T; zend_brk_cont_element *brk_cont_array; int last_brk_cont; int current_brk_cont; zend_try_catch_element *try_catch_array; int last_try_catch; /* static variables support */ HashTable *static_variables; zend_op *start_op; int backpatch_count; zend_uint this_var; char *filename; zend_uint line_start; zend_uint line_end; char *doc_comment; zend_uint doc_comment_len; zend_uint early_binding; /* the linked list of delayed declarations */ void *reserved[ZEND_MAX_RESERVED_RESOURCES]; }; typedef struct _zend_op_array zend_op_array;
이 구조는 비교적 복잡합니다. 현재로서는 가장 기본적인 분야만 소개합니다.
1.type:
op_array의 유형입니다. 가장 먼저 주목해야 할 점은 PHP 코드가 컴파일된 후 zend_op_array 포인터가 반환되더라도 실제로는 하나 이상의 zend_op_array 구조가 생성될 수 있다는 것입니다. 이 구조 function_name, num_args 등과 같은 일부 필드입니다. 이 zend_op_array 구조는 함수와 특정 연결이 있는 것처럼 보일 수 있습니다. 실제로 사용자 정의 함수와 사용자 정의 클래스 메소드는 모두 zend_op_array 구조입니다. 예를 들어, 사용자 정의 함수는 전역 함수 기호 테이블인 GLOBAL_FUNCTION_TABLE에 저장되며 함수 이름을 통해 이 테이블에서 검색할 수 있습니다. 그렇다면 컴파일 후 반환되는 zend_op_array 포인터는 무엇일까요? 사실 컴파일 후 반환되는 zend_op_array는 실행을 위한 진입점이기도 합니다. 즉, 어떤 함수에도 없는 전역 코드로 구성된 op_array라고 볼 수도 있습니다. 몸. 그러나 전역 코드, 사용자 정의 함수 및 사용자 정의 메서드는 모두 동일한 유형 값(2)을 갖습니다. , 유형의 가능한 값에 대한 매크로 정의는 다음과 같습니다.
#define ZEND_INTERNAL_FUNCTION 1 #define ZEND_USER_FUNCTION 2 #define ZEND_OVERLOADED_FUNCTION 3 #define ZEND_EVAL_CODE 4 #define ZEND_OVERLOADED_FUNCTION_TEMPORARY 5
전역 코드, 사용자 함수 및 사용자 메소드가 모두 가장 일반적인 유형이기도 한 ZEND_USER_FUNCTION에 해당하는 것을 볼 수 있습니다. ZEND_EVAL_CODE는 함수의 eval PHP 코드에 해당하므로 eval 함수 매개변수의 PHP 코드도 별도의 zend_op_array로 컴파일될 것이라고 상상할 수 있습니다.
2.function_name
op_array가 사용자 정의 함수 또는 메소드를 컴파일하여 생성된 경우 이 필드는 함수의 이름에 해당합니다. 전역 코드이거나 eval 부분의 코드인 경우 이 필드는 다음과 같습니다. 제어.
3.opcodes
이 필드 유형은 zend_op *이므로 zend_op의 배열입니다. 이 배열은 이 컴파일 과정에서 생성된 ops를 저장합니다. zend_op를 모르는 경우 이전 기사 소개를 읽을 수 있습니다. OPcode에서 이 필드는 가장 중요한 부분이며, zend_execute는 궁극적으로 여기에 저장된 작업을 실행합니다.
이제 op_array 매개변수에 대한 기본적인 이해가 끝났으므로 실행에 들어갑니다.

실행과정에 대한 자세한 설명

execute函数开始的时候是一些基础变量的申明,其中zend_execute_data *execute_data;是执行期的数据结构,此变量在进行一定的初始化之后将会被传递给每个op的handler函数作为参数,op在执行过程中随时有可能改变execute_data中的内容。
第14行zend_vm_enter 这个跳转标签是作为虚拟机执行的入口,当op中涉及到函数调用的时候,就有可能会跳转到这里来执行函数体。
第16行到第19行为execute_data分配空间
第21行到第32行主要是对execute_data进行一些初始化,以及保存现场工作,要保存现场是因为在进入函数调用的时候,需要保存当前一些运行期间的数据,在函数调用结束之后再进行还原,可以想象为操作系统中进程调度,当进程在调出的时候需要保存寄存器等上下文环境,而当进程被调入的时候再取出来继续执行。
第41行到第51行主要是在当前动态符号表中加入$this变量,这个是在调用对象的方法时才有必要进行。
第58行开始的while无限循环就是开始执行op_array中的opcodes了,在第66行中调用当前执行的op的handler:
EX(opline)->handler(execute_data TSRMLS_CC))
然后如果handler的返回值小于0则循环继续,如果大于0则进入一个switch结构:
当返回值为1时:execute函数将返回,执行也就结束了。
当返回值为2时:op_array被重新设置,并跳转到zend_vm_enter ,这个一般是函数调用或则执行eval函数中的代码,将在新的上下文执行相关函数的op_array
当返回值为3时:循环体继续继续执行,当然再继续执行之前,EX(opline)已经往后移了一位(可能多位),也就是已经指向了后面一个新的opline,于是继续执行新的opline
当返回其他值时:结束循环,报错,结束应该用return,也就是返回1
在op的handler中返回特定的值都被定义成了宏,例如{PHPSRC}/Zend/zend_execute.c中定义的:
#define ZEND_VM_NEXT_OPCODE() / CHECK_SYMBOL_TABLES() / EX(opline)++; / ZEND_VM_CONTINUE() #define ZEND_VM_SET_OPCODE(new_op) / CHECK_SYMBOL_TABLES() / EX(opline) = new_op #define ZEND_VM_JMP(new_op) / CHECK_SYMBOL_TABLES() / if (EXPECTED(!EG(exception))) { / EX(opline) = new_op; / } / ZEND_VM_CONTINUE() #define ZEND_VM_INC_OPCODE() / EX(opline)++
以及在{PHPSRC}/Zend/zend_vm_execute.c中定义的:
#define ZEND_VM_CONTINUE() return 0 #define ZEND_VM_RETURN() return 1 #define ZEND_VM_ENTER() return 2 #define ZEND_VM_LEAVE() return 3 #define ZEND_VM_DISPATCH(opcode, opline) return zend_vm_get_opcode_handler(opcode, opline)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
简单介绍功能
ZEND_VM_NEXT_OPCODE():移动到下一条op,返回0,不进入switch,循环继续(这个是最常用到的)
ZEND_VM_SET_OPCODE(new_op):当前opline设置成new_op
ZEND_VM_JMP(new_op) :当前opline设置成new_op,返回0,不进入switch,循环继续
ZEND_VM_INC_OPCODE():仅仅移动到下一条op

执行环境的切换

在前面的内容已经提到,用户自定义函数,类方法,eval的代码都会编译成单独的op_array,那么当进行函数调用等操作时,必然涉及到调用前的op_array执行环境和新的函数的op_array执行环境的切换,这一段我们将以调用用户自定义函数来介绍整个切换过程如何进行。
介绍此过程前必须了解执行环境的相关数据结构,涉及到执行环境的数据结构主要有两个:
1. 执行期全局变量结构
相关的定义在{PHPSRC}/Zend/zend_globals_macros.h:
/* Executor */ #ifdef ZTS # define EG(v) TSRMG(executor_globals_id, zend_executor_globals *, v) #else # define EG(v) (executor_globals.v) extern ZEND_API zend_executor_globals executor_globals; #endif
这里是一个条件编译,ZTS表示线程安全启用,为了简化,我们这里以非线程安全模式的情况下来介绍,那么执行期的全局变量就是executor_globals,其类型为zend_executor_globals, zend_executor_globals的定义在{PHPSRC}/Zend/zend_globals.h,结构比较庞大,这里包含了整个执行期需要用到的各种变量,无论是哪个op_array在执行,都共用这一个全局变量,在执行过程中,此结构中的一些成员可能会改变,比如当前执行的op_array字段active_op_array,动态符号表字段active_symbol_table可能会根据不同的op_array而改变,This指针会根据在不同的对象环境而改变。
另外还定义了一个EG宏来取此变量中的字段值,此宏是针对线程安全和非线程安全模式的一个封装。
2.每个op_array自身的执行数据
针对每一个op_array,都会有自己执行期的一些数据,在函数execute开始的时候我们能看到zend_vm_enter跳转标签下面就会初始一个局部变量execute_data,所以我们每次切换到新的op_array的时候,都会为新的op_array建立一个execute_data变量,此变量的类型为zend_execute_data的指针,相关定义在{PHPSRC}/Zend/zend_compile.h:
struct _zend_execute_data { struct _zend_op *opline; zend_function_state function_state; zend_function *fbc; /* Function Being Called */ zend_class_entry *called_scope; zend_op_array *op_array; zval *object; union _temp_variable *Ts; zval ***CVs; HashTable *symbol_table; struct _zend_execute_data *prev_execute_data; zval *old_error_reporting; zend_bool nested; zval **original_return_value; zend_class_entry *current_scope; zend_class_entry *current_called_scope; zval *current_this; zval *current_object; struct _zend_op *call_opline; };
可以用EX宏来取其中的值:#define EX(element) execute_data->element
这里只简单介绍其中两个字段:
 opline: 当前正在执行的op。
 prev_execute_data:  op_array环境切换的时候,这个字段用来保存切换前的op_array,此字段非常重要,他能将每个op_array的execute_data按照调用的先后顺序连接成一个单链表,每当一个op_array执行结束要还原到调用前op_array的时候,就通过当前的execute_data中的prev_execute_data字段来得到调用前的执行器数据。
在executor_globals中的字段current_execute_data就是指向当前正在执行的op_array的execute_data。  
再正式介绍之前还需要简单的介绍一下用户自定义函数的调用过程,详细的过程以后再函数章节中专门介绍,这里简单的说明一下:
在调用函数的时候,比如test()函数,会先在全局函数符号表中根据test来搜索相关的函数体,如果搜索不到则会报错函数没有定义,找到test的函数体之后,取得test函数的op_array,然后跳转到execute中的goto标签:zend_vm_enter,于是就进入到了test函数的执行环境。
下面我们将以一段简单的代码来介绍执行环境切换过程,例子代码:

这段代码非常简单,这样方便我们介绍原理,复杂的代码读者可以举一反三。此代码编译之后会生成两个op_array,一个是全局代码的op_array,另外一个是test函数的op_array,其中全局代码中会通过函数调用进入到test函数的执行环境,执行结束之后,会返回到全局代码,然后代码结束。
下面我们分几个阶段来介绍这段代码的过程,然后从中可以知道执行环境切换的方法。
1. 进入execute函数,开始执行op_array ,这个op_array就是全局代码的op_array,我们暂时称其为op_array1
首先在execute中为op_array1建立了一个execute_data数据,我们暂时命名为execute_data1,然后进行相关的初始化操作,其中比较重要的是:
EX(op_array) = op_array; // 设置op_array字段为当前执行的op_array,也就是全局代码的op_array1 EX(prev_execute_data) = EG(current_execute_data);//将全局执行数据中保存的当前op_array执行数据保存到op_array1的execute_data1的prev_execute_data字段,由于这是执行的第一个op_array,所以prev_execute_data实际上是空值,然后将执行期全局变量的current_execute_data设置成execute_data1,然后设置execute_data1的当前执行op,这样就可以开始执行当前的op了
2. 在op_array1执行到test函数调用的的时候,首先从全局函数符号表中找到test的函数体,将函数体保存在execute_data1的function_state字段,然后从函数体中取到test的op_array,我们这里用op_array2来表示,并将op_array2赋值给EG(active_op_array):
EG(active_op_array) = &EX(function_state).function->op_array;
于是执行期全局变量的动态op_array字段指向了函数test的op_array,然后用调用ZEND_VM_ENTER();这个时候会先回到execute函数中的switch结构,并且满足以下case
case 2: op_array = EG(active_op_array); goto zend_vm_enter;
EG(active_op_array)之前已经被我们设置为test函数的op_array2,于是在函数execute中,op_array变量就指向了test的op_array2,然后跳转到zend_vm_enter。
3. 跳转到zend_vm_enter之后其实又回到了类似1中的步骤,此时为test的op_array2建立了它的执行数据execute_data,我们这里用execute_data2来表示。1과 조금 다른 점은 EX(prev_execute_data) = EG(current_execute_data); 이때 current_execute_data = excute_data1이고, 그 다음에는 EG(current_execute_data) = excute_data이므로 current_execute_data는 다음과 같다. Execute_data2를 테스트하고 전역 코드의 Execute_data1이 Execute_data2의 prev_execute_data 필드에 저장됩니다. 이때 환경전환이 완료되어 테스트 기능이 실행되기 시작한다.
4. 테스트 함수가 실행되면 전역 코드 실행 환경인 호출 전 실행 환경으로 돌아갑니다. 이 단계에서 가장 중요한 작업은 EG(current_execute_data) = EX(prev_execute_data)입니다. 3번의 (prev_execute_data)를 글로벌 코드의 Execute_data1로 설정하였기 때문에 현재 실행 데이터가 글로벌 코드의 실행 데이터가 됩니다. 이로써 함수 테스트 실행 환경은 성공적으로 글로벌 코드 실행 환경으로 복귀됩니다. 이렇게 하면 실행 환경 전환 프로세스가 완료됩니다. 깊은 함수 호출의 경우 실행 데이터로 구성된 단일 연결 목록이 더 길어집니다.

확장 읽기

이 기사의 주제 목록은 다음과 같습니다.

PHP 핵심 탐색: SAPI 인터페이스에서 시작
PHP 핵심 탐색: 요청의 시작과 끝
PHP 코어 탐색: 일회성 요청 수명 주기
PHP 커널 탐색: 단일 프로세스 SAPI 수명 주기
PHP 커널 탐색: 다중 프로세스/스레드 SAPI 수명 주기
PHP 커널 탐색: Zend 엔진
PHP 커널 탐색 : SAPI 재검토
PHP 커널 탐색: Apache 모듈 소개
PHP 커널 탐색: mod_php5를 통한 PHP 지원
PHP 커널 탐색: Apache 실행 및 후크 기능
PHP 커널 탐색: 임베디드 PHP
PHP 커널 탐색: PHP FastCGI
PHP 커널 탐색: PHP 스크립트 실행 방법
PHP 커널 탐색: PHP 스크립트 실행 세부 정보
PHP 커널 탐색: Opcode OpCode
PHP 커널 탐색: PHP의 Opcode
PHP 커널 탐색: 인터프리터의 실행 프로세스
PHP 커널 탐색: 변수 개요
PHP 커널 탐색: 변수 저장소 및 유형
PHP 커널 탐색: PHP의 해시 테이블
PHP 커널 탐색: Zend 이해
PHP 커널 탐색: PHP 해시 알고리즘 설계
PHP 커널 탐색: 해시 테이블 번역 기사
PHP 커널 탐색: 해시 충돌 공격이란 무엇입니까?
PHP 커널 탐색: 상수 구현
PHP 커널 탐색: 변수 저장
PHP 커널 탐색: 변수 유형
PHP 커널 탐색: 변수의 값 연산
PHP 커널 탐색: 변수 생성
PHP 커널 탐색: 사전 정의된 변수
PHP 커널 탐색: 변수 검색
PHP 커널 탐색: 변수의 유형 변환
PHP 커널 탐색: 약한 유형 변수 구현
PHP 커널 탐색: 구현 정적 변수
PHP 코어 탐색: 변수 유형 힌트
PHP 코어 탐색: 가변 수명 주기
PHP 코어 탐색: 변수 할당 및 소멸
PHP 코어 탐색: 변수 범위
PHP 코어 탐색: 이상한 변수 이름
PHP 코어 탐색: 변수 값 및 유형 저장
PHP 코어 탐색: 전역 변수 전역
PHP 코어 탐색: 변수 유형 변환
PHP 코어 탐색: 메모리 관리 시작
PHP 커널 탐색: Zend Memory Manager
PHP 커널 탐색: PHP 메모리 관리
PHP 커널 탐색: 메모리 적용 및 파괴
PHP 커널 탐색: 참조 계산 및 쓰기 시 복사
PHP 커널 탐색: PHP5. 3의 가비지 수집 메커니즘
PHP 커널 탐색: 메모리 관리의 캐시
PHP 커널 탐색: 쓰기 시 복사 COW 메커니즘
PHP 커널 탐색: 배열 및 연결 목록
PHP 코어 탐색: 해시 테이블 사용 API
PHP 코어 탐색: 배열 연산
PHP 코어 탐색: 배열 소스 코드 분석
PHP 코어 탐색: 함수 분류
PHP 코어 탐색: 함수 내부 구조
PHP 코어 탐색: 함수 구조 변환
PHP 코어 탐색: 함수 정의 프로세스
PHP 코어 탐색: 함수의 매개변수
PHP 코어 탐색: zend_parse_parameters 함수
PHP 코어 탐색: 함수 반환 값
PHP 코어 탐색: 형식 매개변수 반환 값
PHP 코어 탐색: 함수 호출 및 실행
PHP 코어 탐색: 참조 및 함수 실행
PHP 코어 탐색: 익명 함수 및 클로저
PHP 코어 탐색: 객체 지향 시작
PHP 핵심 탐색: 클래스 구조 및 구현
PHP 핵심 탐색: 클래스의 멤버 변수
PHP 핵심 탐색: 클래스의 멤버 메서드
PHP 핵심 탐색: 클래스 프로토타입 zend_class_entry
PHP 핵심 탐색 : 클래스 정의
PHP 핵심 탐색: 접근 제어
PHP 핵심 탐색: 상속, 다형성 및 추상 클래스
PHP 핵심 탐색: 매직 함수 및 지연 바인딩
PHP 핵심 탐색: 예약 클래스 및 특수 클래스
PHP 핵심 탐색: 객체
PHP 핵심 탐색: 객체 인스턴스 생성
PHP 핵심 탐색: 객체 속성 읽기 및 쓰기
PHP 핵심 탐색: 네임스페이스
PHP 코어 탐색: 인터페이스 정의
PHP 코어 탐색: 인터페이스 상속 및 구현
PHP 코어 탐색: 리소스 리소스 유형
PHP 코어 탐색: Zend 가상 머신
PHP 코어 탐색: 가상 머신의 어휘 분석
PHP 커널 탐색: 구문 분석 가상 머신
PHP 커널 탐색: 중간 코드 opcode 실행
PHP 커널 탐색: 코드 암호화 및 복호화
PHP 커널 탐색: zend_execute의 특정 실행 프로세스
PHP 커널 탐색: 변수 참조 및 계산 규칙
PHP 커널 탐색: 새로운 가비지 수집 메커니즘 설명

위 내용은 PHP 커널 복호화 시리즈: zend_execute의 실행 과정을 관련 내용을 포함하여 소개하고 있으며, PHP 튜토리얼에 관심이 있는 친구들에게 도움이 되기를 바랍니다.

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

Java 병렬 프로그래밍에서 Executor 및 ThreadPool의 사용 분석 Java 병렬 프로그래밍에서 Executor 및 ThreadPool의 사용 분석 Apr 18, 2024 pm 05:33 PM

Executor 인터페이스는 작업 실행 메커니즘을 제공하고 ThreadPool은 작업을 실행하기 위해 스레드 풀을 관리하는 구현입니다. ThreadPool은 newFixedThreadPool()과 같은 Executors 도구 클래스를 사용하여 생성되며, 실행() 메서드를 사용하여 작업을 제출합니다. 실제 사례에서 ExecutorService 및 ThreadPool은 병렬 프로그래밍의 사용을 보여주기 위해 숫자의 제곱합을 계산하는 데 사용됩니다. 고려 사항에는 스레드 풀 크기와 작업 수의 균형 조정, 예외 발생 방지, 사용 후 ThreadPool 닫기 등이 포함됩니다.

C#에서 Array.Sort 함수를 사용하여 배열 정렬 C#에서 Array.Sort 함수를 사용하여 배열 정렬 Nov 18, 2023 am 10:37 AM

제목: Array.Sort 함수를 사용하여 C#에서 배열을 정렬하는 예 텍스트: C#에서는 배열이 일반적으로 사용되는 데이터 구조이므로 배열 정렬 작업이 필요한 경우가 많습니다. C#에서는 배열을 편리하게 정렬할 수 있는 Sort 메서드가 있는 Array 클래스를 제공합니다. 이 문서에서는 C#에서 Array.Sort 함수를 사용하여 배열을 정렬하는 방법을 보여주고 구체적인 코드 예제를 제공합니다. 먼저 Array.Sort 함수의 기본 사용법을 이해해야 합니다. 배열.그래서

PHP 구현 프레임워크: Zend 프레임워크 시작 튜토리얼 PHP 구현 프레임워크: Zend 프레임워크 시작 튜토리얼 Jun 19, 2023 am 08:09 AM

PHP 구현 프레임워크: ZendFramework 입문 튜토리얼 ZendFramework는 PHP에서 개발하고 현재 ZendTechnologies에서 유지 관리하는 오픈 소스 웹 사이트 프레임워크입니다. ZendFramework는 MVC 디자인 패턴을 채택하고 Web2.0 애플리케이션 및 Web Serve 구현을 지원하기 위한 재사용 가능한 코드 라이브러리 시리즈를 제공합니다. ZendFramework는 PHP 개발자들에게 매우 인기 있고 존경받고 있으며 다양한 기능을 갖추고 있습니다.

Zend Framework에서 권한 제어를 위해 ACL(Access Control List)을 사용하는 방법 Zend Framework에서 권한 제어를 위해 ACL(Access Control List)을 사용하는 방법 Jul 29, 2023 am 09:24 AM

Zend Framework에서 권한 제어를 위해 ACL(AccessControlList)을 사용하는 방법 소개: 웹 애플리케이션에서 권한 제어는 중요한 기능입니다. 이는 사용자가 액세스 권한이 있는 페이지와 기능에만 액세스할 수 있도록 하고 무단 액세스를 방지합니다. Zend 프레임워크는 ACL(AccessControlList) 구성 요소를 사용하여 권한 제어를 구현하는 편리한 방법을 제공합니다. 이 기사에서는 Zend Framework에서 ACL을 사용하는 방법을 소개합니다.

Executeupdate와 Execution의 차이점 Executeupdate와 Execution의 차이점 Dec 12, 2023 pm 02:01 PM

Executeupdate와 실행의 차이점: 1. 목적 및 반환 값 3. 실행 시간 5. 성능 고려사항 자세한 소개: 1. 목적 및 반환 값 "executeUpdate()" 메서드는 주로 INSERT, UPDATE 또는 DELETE 작업과 같은 데이터를 수정하는 SQL 문을 실행하는 데 사용됩니다. xecute() 메서드는 더 일반적이며 다음과 같이 사용할 수 있습니다. 데이터 쿼리 및 데이터 수정 등을 포함하여 모든 유형의 SQL 문을 실행합니다.

PHP에서 array_combine 함수를 사용하여 두 배열을 연관 배열로 결합하는 방법 PHP에서 array_combine 함수를 사용하여 두 배열을 연관 배열로 결합하는 방법 Jun 26, 2023 pm 01:41 PM

PHP에는 배열 작업을 더욱 편리하고 빠르게 만들어주는 강력한 배열 함수가 많이 있습니다. 두 배열을 연관 배열로 결합해야 하는 경우 PHP의 array_combine 함수를 사용하여 이 작업을 수행할 수 있습니다. 이 함수는 실제로 한 배열의 키를 다른 배열의 값으로 새로운 연관 배열로 결합하는 데 사용됩니다. 다음으로 PHP에서 array_combine 함수를 사용하여 두 배열을 연관 배열로 결합하는 방법을 설명하겠습니다. array_comb에 대해 알아보기

PHP array_merge_recursive() 함수를 사용하는 간단하고 명확한 방법 PHP array_merge_recursive() 함수를 사용하는 간단하고 명확한 방법 Jun 27, 2023 pm 01:48 PM

PHP로 프로그래밍할 때 배열을 병합해야 하는 경우가 종종 있습니다. PHP는 배열 병합을 완료하기 위해 array_merge() 함수를 제공하지만, 배열에 동일한 키가 존재할 경우 이 함수는 원래 값을 덮어씁니다. 이 문제를 해결하기 위해 PHP는 배열을 병합하고 동일한 키의 값을 유지할 수 있는 array_merge_recursive() 함수도 언어에 제공하여 프로그램 설계를 더욱 유연하게 만듭니다. array_merge

Java 스레드 풀 실행() 메소드를 사용하는 방법 Java 스레드 풀 실행() 메소드를 사용하는 방법 May 10, 2023 pm 11:46 PM

먼저 스레드 풀의 기능을 이해하세요.

See all articles