鍍金池/ 問答/PHP  Python/ python為何效率慢點(diǎn)?PHP跟Python的解釋器都是C寫的,PHP為什么能

python為何效率慢點(diǎn)?PHP跟Python的解釋器都是C寫的,PHP為什么能快點(diǎn)?

其實(shí)用python的人應(yīng)該都是不關(guān)注它性能的人,畢竟寫python確實(shí)很愉快
PHP的核心維護(hù)者花了很多的心血卻提高底層的解釋器效率,為什么Python的維護(hù)者不去呢?


程序員都喜歡用數(shù)據(jù)說話,這里我用的python版本是Python 3.6.2(64位),php版本是PHP 7.0.12(64位),node版本是v6.11.0(64位),Go 1.8.3(64位),C# 基于.Net 4.0,lua 5.1.4

對比

python

import time

calNum = 100000000

def test():
    sum = 0
    for x in range(1, calNum + 1):
        sum += x
    return sum


start = time.time()

test()

end = time.time()

print(end - start)

PHP

<?php

$calNum = 200000000;

function test() {
    $sum = 0;
    global $calNum;
    for ($i = 0; $i < $calNum; $i++) { 
        $sum += $i;
    }
    return $sum;
}

$start = time();

test();

$end = time();

echo ($end - $start);

nodeJS


let calNum = 200000000;

function test() {
    let sum = 0;
    for (var i = 0; i < calNum; i++) {
        sum += i;
    }
    return sum;
}

let start =  new Date().getTime();

test();

let end =  new Date().getTime();

console.log((end - start) / 1000);

Golang

package main

import (
    "fmt"
    "math"
    "time"
)

var calNum = 200000000

func test() int {
    sum := 0
    for i := 0; i < calNum; i++ {
        sum += i
    }
    return sum
}

func main() {
    start := time.Now().UnixNano()
    test()
    end := time.Now().UnixNano()
    fmt.Println(float64(end - start) / math.Pow(10, 9))
}

C#

 private static int calNum = 100000000;

        static int test()
        {
            int sum = 0;
            for (int i = 0; i < calNum; i++)
            {
                sum += i;
            }
            return sum;
        }

        static void Main(string[] args)
        {
            double start = ConvertDateTimeInt(DateTime.Now);
            test();
            double end = ConvertDateTimeInt(DateTime.Now);
            Console.WriteLine(end - start);
            Console.ReadLine();
        }

        /// <summary>
        /// DateTime時(shí)間格式轉(zhuǎn)換為Unix時(shí)間戳格式
        /// </summary>
        /// <param name="time"> DateTime時(shí)間格式</param>
        /// <returns>Unix時(shí)間戳格式</returns>
        public static double ConvertDateTimeInt(DateTime time)
        {
            System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
            return (time - startTime).TotalSeconds;
        }

lua

calNum = 200000000


function test()
    local sum = 0
    for i=0,calNum - 1 do
        sum = i + sum
    end
    return sum
end

local start = os.time()
test()
local endTime = os.time()

print(endTime - start)

執(zhí)行時(shí)間(1億次,2億次)

python

C:\Users\mh\Desktop>python cal.py
7.873001337051392

C:\Users\mh\Desktop>python cal.py
17.40298104286194

PHP

C:\Users\mh\Desktop>php cal.php
5
C:\Users\mh\Desktop>php cal.php
13

PHP 7.1(新下載的)

C:\Users\mh\Desktop>php cal.php
5
C:\Users\mh\Desktop>php cal.php
10

nodeJS

C:\Users\mh\Desktop>node cal.js
1.288

C:\Users\mh\Desktop>node cal.js
2.603

Golang

C:\Users\mh\Desktop>go run cal.go
0.0519903

C:\Users\mh\Desktop>go run cal.go
0.1080017

C#

0.685999155044556

1.52999567985535

lua(just for fun)

C:\Users\mh\Desktop>cal.lua
1

C:\Users\mh\Desktop>cal.lua
2

PHP還是比python快的,不過在腳本語言中node更快,Go挺快的

回答
編輯回答
糖豆豆

PHP的核心維護(hù)者花了很多的心血卻提高底層的解釋器效率,為什么Python的維護(hù)者不去呢?

可能是因?yàn)?php 以前太慢了唄。

2018年8月7日 12:17
編輯回答
款爺

python并不一定慢,許多Python的科學(xué)計(jì)算庫通過用C來編寫可以獲得和全用c或者c++寫的程序相同或者慢一到兩倍的體驗(yàn)。

很多人認(rèn)為他慢。他其實(shí)也確實(shí)慢。
一是GIL,其實(shí)GIL也只是CPython python解釋器的特性,其主要是在多核機(jī)器上python無法獲得多核所帶來的性能優(yōu)勢。單核其實(shí)就差不多了。
樓下起風(fēng)了不認(rèn)可。首先大多數(shù)Python程序都是運(yùn)行在CPython上的。無數(shù)用c語言為Python編寫的好的庫也是只能運(yùn)行在cpyhon上的。所以GIL是大多數(shù)Python程序繞不開的東西。你說多進(jìn)程可以解決。但是這也導(dǎo)致了一個(gè)問題就是進(jìn)程間的數(shù)據(jù)共享問題。因?yàn)椴辉谝粋€(gè)進(jìn)程中共享內(nèi)存空間這種高效的共享方式不能使用(當(dāng)然GIL也是為了處理多線程共享內(nèi)存所帶來的風(fēng)險(xiǎn)而設(shè)置的。)這樣你多線程間通信也會(huì)帶來性能的損耗。當(dāng)然你說可以通過多線程解決也沒錯(cuò),但是也不能說GIL不是導(dǎo)致大多數(shù)python慢的原因。

二是python是一門解釋形語言,其是邊運(yùn)行邊將python字節(jié)碼編譯成系統(tǒng)可以執(zhí)行的可執(zhí)行代碼。這會(huì)帶來一定的性能損耗,但是一個(gè)程序的快慢主要還是由其熱點(diǎn)部分決定。通過將熱點(diǎn)部分使用C語言編寫,基本就可以獲得很好的性能。
樓下起風(fēng)了說python運(yùn)行一次后編碼就完成了。我想他可能沒有理解解釋型語言的編譯。 Python在運(yùn)行前編譯好的文件是Python字節(jié)碼。如果沒有Python虛擬機(jī)是不能運(yùn)行的。當(dāng)在運(yùn)行的時(shí)候Python虛擬機(jī)又吧Python字節(jié)碼翻譯成可以被CPU執(zhí)行的二進(jìn)制字節(jié)碼。而像C語言這種是直接編譯連接就可以生成直接被機(jī)器執(zhí)行的二進(jìn)制碼。

其實(shí)對于大型應(yīng)用影響其性能的首先是架構(gòu)其次是程序編寫邏輯然后是語言特性。大部分系統(tǒng)瓶頸都輸數(shù)據(jù)庫讀取。加個(gè)redis緩存就可以獲得不錯(cuò)的性能提升。 ins還不是用django撐起了全球最大圖片分享網(wǎng)站。
手機(jī)打的錯(cuò)別字可能多一點(diǎn)??

import time

calNum = 100000000

def test():
    sum = 0
    for x in range(1, calNum + 1):
        sum += x
    return sum

def test1():
    sum = 0
    for x in xrange(1, calNum + 1):
        sum += x
    return sum

def test2(mylist):
    sum = 0
    for x in mylist:
        sum += x
    return sum

def test3():
    sum = 0
    i = 0
    while i < calNum:
        sum += i
        i += 1
    return sum

start = time.time()
test()
end = time.time()
print 'test time: {0}'.format(str(end-start))

start = time.time()
test1()
end = time.time()
print 'test1 time: {0}'.format(str(end-start))

mylist = range(1, calNum + 1)
start = time.time()
test2(mylist)
end = time.time()
print 'test2 time: {0}'.format(str(end-start))

start = time.time()
test3()
end = time.time()
print 'test3 time: {0}'.format(str(end-start))

四種不同的寫法
test time: 7.10620498657
test1 time: 4.30882191658
test2 time: 4.70718193054
test3 time: 8.60779190063

四種不同的寫法 獲得時(shí)間也不同。 我之后再寫一個(gè)鏈接了c語言庫的實(shí)例補(bǔ)上。

2018年8月21日 23:26
編輯回答
墨小羽

不清楚樓主說的效率是指哪方面的效率?

樓主有做過對比測試嗎?

python3.6開始已經(jīng)開始針對GIL的問題進(jìn)行解決了,并準(zhǔn)備摒棄這個(gè)東西了??梢允媚恳源?/p>

2018年8月3日 11:49
編輯回答
情已空

我對樓上的解釋持懷疑態(tài)度。如果你覺得GIL是導(dǎo)致慢的原因,大可以用多進(jìn)程替代,GIL的問題本質(zhì)是導(dǎo)致多線程是分時(shí)復(fù)用而已(如果一個(gè)線程不間斷地在 Python 2 中運(yùn)行 1000 字節(jié)碼指令,或者不間斷地在 Python 3 運(yùn)行15 毫秒,那么它便會(huì)放棄 GIL,而其他線程可以運(yùn)行)。而且由于GIL本身,甚至可以導(dǎo)致多線程比單線程還慢。而且GIL是CPython的,大可用別的版本的Python實(shí)現(xiàn)。再者,并不是每個(gè)程序都有必要通過多線程去實(shí)現(xiàn),而且事實(shí)上大多數(shù)人寫的程序就是單線程的,所以這不能成為你的Python程序慢的借口。

Python說到底是一門高級語言,高級語言比低級語言慢是很正常的事情,你去看看leetcode里面解題時(shí)間vs不同語言的柱狀圖就知道差距了,反正不是樓上說的一兩倍。再說上面提到的邊運(yùn)行邊編譯字節(jié)碼的問題,除了主腳本以外,如果別的py文件沒做改動(dòng),且運(yùn)行的python解釋器版本相同,它是不會(huì)重新編譯的,而且python添加了編譯優(yōu)化選項(xiàng),所以我覺得這也不是個(gè)很好的理由。比如你寫了一個(gè)for循環(huán),循環(huán)上萬次,里面就只是數(shù)據(jù)結(jié)構(gòu)動(dòng)態(tài)重綁定之類的簡單操作或者就是簡單的加法(沒有類型的加法),那你能說是編譯,加載,連接是主要導(dǎo)致慢的原因嘛?再說很多比Python快的面向?qū)ο蟮恼Z言也會(huì)用到虛擬機(jī),總不能一股腦全部賴在這個(gè)中間步驟上。

至于為什么慢,又回到高級語言的話題上,python是1.高級的 2.動(dòng)態(tài)的,戳這里
樓上提到主要解決熱點(diǎn)問題是一致推薦的,一般prototype用python編寫,較慢的代碼會(huì)用低級語言重構(gòu)。

當(dāng)我們一定要討論某種語言快慢的時(shí)候,是不是應(yīng)該剖析語言本身的特性和準(zhǔn)則,而并不是針對某個(gè)特定實(shí)現(xiàn)版本,雖然即使這個(gè)版本是大多數(shù)人用的。

只是本人基于自己的理解YY的,大家討論哈~

2017年11月4日 19:04
編輯回答
紓惘

看到其他答案都在為Python性能擔(dān)憂,我這邊也提供一個(gè)對性能提升的方法,題目的Python代碼幾乎不用變,只要加個(gè) jit 修飾器即可,性能可秒殺其他語言,并且規(guī)模越大優(yōu)勢越明顯:

import time
from numba import jit
calNum = 300000000

@jit
def test():
    sum = 0
    for x in range(1, calNum + 1):
        sum += x
    return sum


start = time.time()

test()

end = time.time()

print(end - start)

數(shù)字直接飆到3億,運(yùn)行一下看看,你一定會(huì)回來贊我的。

這個(gè)模塊可以在 https://www.lfd.uci.edu/~gohl... 下載。

2017年4月22日 16:40
編輯回答
涼汐

韓天峰大大寫到:

benchmarksgame 上面的測試基本上都是密集計(jì)算的。PHP 和 Python(CPython) 目前都沒有 JIT,PHP
能勝出只能說明底層 VM 性能比 Python 的要好。實(shí)際上 PHP 語言官方開發(fā)組從 5.4 時(shí)代就一直在優(yōu)化 VM 的性能。PHP7版本對底層的數(shù)據(jù)結(jié)構(gòu)進(jìn)行了很大的改造,相比 5.6 提升了 1 倍以上的性能。而 Python 3 相比 Python 2性能上反而是在退步。 密集計(jì)算場景,靜態(tài)語言和 有 JIT 的動(dòng)態(tài)語言 會(huì)有很大的優(yōu)勢??梢钥吹?Node.js(基于 V8 引擎)的測試成績遠(yuǎn)超 PHP 和 Python 。前者的計(jì)算指令是直接作為 CPU 指令執(zhí)行的,后者計(jì)算實(shí)際上是 VM
上的高級指令,實(shí)現(xiàn)原理上有很大差異。不過,各位 PHPer 也別灰心,PHP 官方開發(fā)組已經(jīng)在開發(fā) JIT 特性了,也許下個(gè)版本 PHP就會(huì)攜帶 JIT ,到時(shí)在密集計(jì)算場景下將會(huì)和 Node.js 在同一數(shù)量級。另外再說句,PHP、Python、Node.js都是寫應(yīng)用軟件的,語言的計(jì)算性能沒那么重要。你的程序如果對性能敏感,C/C++/GO/Rust 這些靜態(tài)編程語言才是最好的選擇。

同為動(dòng)態(tài)語言,python的性能為何只有PHP的五分之一?

2017年2月20日 21:20