항상 php가 java보다 느리다고 하는데 오늘은 이론과 실제 테스트로 php가 정말 느리는지, 느린지 어디 있는지 알아보겠습니다.
1: 실행 모드 대비
자바: 일반적으로 자바 언어로 개발된 웹사이트 프로젝트는 명령어 라인 모드에서 실행되며, 일부는 실행 가능하다.파일(.exe) 모양형식 운행
php:주로 cgi모드로 동작하며, 부분적으로는 cli모드로 동작한다. 예를 들면 swoole 확장.
php cgi 모드에서 들어오는 모든 요청은 php 코드, 생성 프로세스, 진행 과정을 거쳐야 합니다.과정 전환에 적지 않은 비용이 든다.자원
최적화 방안: 1: FPM 프로세스 풀은 프로세스 재사용을 위해 활성 프로세스를 유지합니다.
2: swoole을 사용하여 php를 cli 모드로 실행하며, 이 패턴은 자바와 유사하다.
2: 코드 실행 모드
java: 실행 전에 jvm으로 컴파일해야 하는 바이트코드(cpu가 아닌 바이트코드), 코드 실행 다이렉트 워드바이트 코드 또는 컴파일시스템 바이너리 실행
php: 요청이 들어올 때마다 코드 분석 -> 해석 -> 컴파일 opcode -> 실행되는 프로세스,앞 3단계 자바보다모두 초과 손실이다.
최적화 방안 : php 오프캐시 캐시(5.5 이후 공식 셀프 확장)를 열어 앞의 3단계를 생략할 수 있다.중복되는 업무
php 실행 흐름 참고 : PHP 실행 흐름 약술
3. 언어 특성
전체 언어 컴파일 실행 흐름에서 볼 때, php가 위의 최적화를 거치는 효율은 java와 동등해야 한다. php와 java를 언어적으로 한 번만 테스트한다.
테스트 환경: 윈도 10 64비트 cpui5 메모리 8g
자바 버전: jdk 10
php 버전: php 8.14
테스트 기능: 두 언어로 동일한 데이터량(2w개의 정수)의 버블 정렬을 구현하고 쌍방의 실행 시간을 비교한다.
코드는 다음과 같습니다.
자바 코드
public class Test {
public static void main(String[] args) {
long st=System.currentTimeMillis();
int count=20000;//이 숫자는 php 실행 시간을 고려하여 이것을 선택하였으며, 클수록 java에게 유리하다
int[] arr=new int[count];
//배열 난수
for (int i=0;i<count;i++){
final double d = Math.random();
arr[i] = (int)(d*count);
}
System.out.println("데이터 생성용 시간="+(System.currentTimeMillis()-st));
for(int i=0;i<arr.length-1;i++){
for(int j=0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
System.out.println("모두 시간이 걸리다="+(System.currentTimeMillis()-st));
}
}
php 코드
<?php
/**
* Created by PhpStorm.
* User: 05
* Date: 2021/12/27
* Time: 10:50
*/
class Test
{
public function msort(){
$arr=[];
$count=20000;//이 데이터가 크면 오래 걸리므로 멀티테스트를 거쳐 2w가 적당하다
$st=microtime(true);
//난수 할당 생성
for ($i=0;$i<$count;$i++){
$arr[$i]=mt_rand(0,$count);
}
echo "데이터 생성용 시간=".(microtime(true)-$st);
for ($i=0;$i<$count-1;$i++){
for ($j=0;$j<$count-1-$i;$j++){
if ($arr[$j]>$arr[$j+1]){
$temp=$arr[$j];
$arr[$j]=$arr[$j+1];
$arr[$j+1]=$temp;
}
}
}
echo "총사용시간=".(microtime(true)-$st);
}
}
$t=new Test();
$t->msort();
열매를 맺다
java: 무작위로 2w개의 정수 생성에 3밀리초, 데이터 생성 후 2w개의 정수 정렬까지 800밀리초 정도가 소요되는데 여기서 여러 번 테스트하여 시간 차이가 크지 않다
PHP:opcache와 jit를 켜지 않음
난수 생성 시간: 1밀리초 이상, 전체 정렬 완료소요시간:13초 남짓…
php와 java의 실행 효율을 시험하기 때문에, php는 한 번 컴파일되지만, 전체 효율은 십여 배 차이가 나기 때문에 결과는 여전히 나를 놀라게 한다.
결론:
위에서 java를 분석하면 php의 전체 컴파일러 실행 흐름과 비슷할 것이다. 여기서 php도 여러 번 컴파일러를 하지 않기 때문에 php의 Zend 밖에 되지 않는다.VM 가상 머신의 opcode 실행의 효율이 JVM의 바이트코드 실행의 효율보다 못하다. php는 약한 타입 언어이기 때문이다. opcode 실행 때마다 변수 유형을 판단해야 한다. 강한 타입 언어처럼 정확한 명령 변환은 할 수 없다. 그러나 PHP 8.0 이후에도 JIT 적시 컴파일 기술을 사용한다.
이제 PHP의 지트를 켜서 한번 테스트해보도록 하겠습니다
결과: 총 소요시간은 3초 남짓으로, 처음 13초보다 질적인 향상은 확실하지만, 자바의 800밀리초 비율과는 확실히 차이가 있다
요약:PHP는 실행 모드, 컴파일 프로세스, 언어 실행 효율 면에서 자바보다 빠르지 않지만, 그에 상응하는 최적화를 통해 PHP도 인터넷에서 말하는 것만큼 큰 차이가 없으며, 특히 현재 웹 프로그래밍이 IO를 주요 제약으로 하는 시대에는 기본적으로 PHP는 자바와 견줄 만한 효율성을 달성할 수 있으며, 또한 PHP는 모듈 분할, 핫 업데이트와 같은 프로젝트 관리에 있어 고유한 이점을 가지고 있기 때문에 자바 또는 PHP를 사용하여 프로젝트 요구 사항에 따라 자신의 선택을 이해할 수 있다.
다음은 JVM 가상 머신 실행, 인용 온라인 요약입니다
자바 가상 머신의 실행 효율은 어떻습니까?
핫스팟은 여러 가지 기술을 응용하여 제시하였다i의 성능과 최고 성능, 즉 컴파일이 가장 중요한 기술 중 하나다.즉시 컴파일하여 프로그램을 만들고 재프로그래밍하는 것이 28법칙에 부합한다는 가정, 즉 코드의 20%가 계산 자원의 80%를 차지한다.
많은 부분을 차지하는 잘 안 쓰는 디아마에게지네틱, 우리는 시간을 들여 기계 코드로 컴파일할 필요 없이 실행 해석을 하는 방법으로 동작하는 한편, 작은 부분만을 차지하는 핫스팟 코드에 대해서는 기계 코드로 컴파일할 수 있어 이상적인 동작속도에 도달했다.
이론상으로는 컴파일된 자바도 프로그램의 실행 효율이 C++ 프로그램을 초과할 수 있습니다.이는 정적 컴파일에 비해 프로그램의 런타임 정보를 즉시 컴파일하고 그에 따라 최적화할 수 있기 때문이다.예를 들어, 우리는 가상 접근법이 객체 지향 다형성을 달성하기 위해 사용되는 것을 알고 있다.가상 메서드 호출의 경우 여러 개의 대상 메서드에 의해 호출되지만 실제로 실행 중인 메서드 중 하나만 호출될 수 있습니다.이 정보는 인스턴트 컴파일러에 의해 이용될 수 있으며, 가상 메소드 호출의 오버헤드를 회피하기 때문에 정적 컴파일된 C++ 프로그램보다 더 높은 성능을 얻을 수 있다.
다양한 장면의 요구에 부응하기 위해 HotSpot는 C1, C2와 Graal…까지 여러 개의 인스턴트 컴파일러를 내장하고 있는데, 이는 컴파일 시간과 생성된 코드의 실행 효율 사이에서 취사선택하기 위함이다.C1은 클라이언트 컴파일러라고 불리며 부팅을 지향합니다.성능이 요구되는 클라이언트 GUI 프로그램은 최적화 수단이 비교적 간단하여 컴파일 시간이 짧습니다.C2 서버 컴파일러라고도 하는 서버 컴파일러는 피크 성능을 요구하는 서버 프로그램을 지향하며, 컴파일 시간이 상대적으로 복잡하기 때문에 최적화합니다.길지만 diamagnetic을 동시에 생성하는 실행 효율이 높다.
자바 7 이후, HotSpot 기본적으로 계층적 컴파일을 사용합니다. 핫스팟은 C1에 의해 먼저 컴파일되고 핫스팟의 핫스팟은 C2에 의해 컴파일됩니다.HotSpot의 즉각적인 컴파일은 응용 프로그램의 정상적인 동작을 방해하지 않기 위해 별도의 컴파일 스레드로 진행됩니다..HotSpot은 CPU의 수에 따라 컴파일 스레드 수를 설정하고 C1과 C2 컴파일러에 1:2로 설정합니다.
계산 자원이 충분한 경우 바이트코드의 해석출 실행과 즉시 컴파일을 동시에 할 수 있다.컴파일이 완료된 머신코드는 다음 번에 메소드가 호출될 때 부팅되며 원래의 해석을 대체하여 실행된다
'개발 꿀팁 > PHP' 카테고리의 다른 글
PHP 디버깅 - 방식 (0) | 2022.07.09 |
---|---|
php 카스로 SSO 싱글 로그인 및 로그아웃 기능 구현 (0) | 2022.07.09 |
PHP 포니, 포니, 포니 분석편찬 실현 (0) | 2022.07.09 |
php7 curl을 로드할 수 없는 문제 해결 및 반성 (0) | 2022.07.08 |
PHP 개발 환경 구축(Apache+PHP+MySQL) (0) | 2022.07.08 |