簡體   English   中英

記錄執行時間:計算機如何快速計算出算術?

[英]Recording time of execution: How do computers calculate arithemetic so fast?

一開始我的問題似乎很基本,但請耐心等待。

我編寫了以下代碼,以測試python從1計數到1,000,000需要多長時間。

import time

class StopWatch:
    def __init__(self, startTime = time.time()):
        self.__startTime = startTime
        self.__endTime = 0

    def getStartTime(self):
        return self.__startTime

    def getEndTime(self):
        return self.__endTime



    def stop(self):
        self.__endTime = time.time()



    def start(self):
        self.__startTime = time.time()

    def getElapsedTime(self):
        return self.__endTime - self.__startTime


count = 0
Timer = StopWatch()
for i in range(1, 1000001):
    count += i

Timer.stop()
total_Time = Timer.getElapsedTime()
print("Total time elapsed to count to 1,000,000: ",total_Time," milliseconds")

我計算出令人驚訝的短時間跨度。 是0.20280098915100098毫秒。 我首先要問: 這是正確的嗎?

我希望執行時間至少為2或3毫秒,但我沒想到它可以在不到半毫秒的時間內完成計算!

如果這是正確的,那將引出我的第二個問題: 為什么這么快?

我知道CPU本質上是為算術而構建的,但我仍然不希望它能夠在十分之二毫秒的時間內達到百萬。

就像@jonrsharpe所說的那樣,也許您被時間計量單位欺騙了。

不過,第三代Intel i7能夠達到120 + GIPS(即每秒數十億次基本操作),因此,假設所有緩存命中且沒有上下文切換(簡單地說,沒有意外等待),它可以很容易地從0到1G計數。說時間甚至更多。 可能不是使用Python,因為它有一些開銷,但仍然可行。

解釋現代CPU如何實現如此“瘋狂”的速度是一個廣泛的話題,實際上是不止一種技術的協作:

  1. 動態調度程序將重新排列基本指令,以盡可能減少沖突(因此,等待)
  2. 精心設計的緩存將立即提供代碼和(盡管對於該基准測試而言,問題較少)。
  3. 動態分支預測器將分析代碼並推測分支條件(例如“ for循環是否結束?”),以預測發生跳躍的可能性很高,並且“獲勝”。
  4. 一個好的編譯器將通過重新布置指令來減少沖突或使循環更快(通過展開,合並等)來提供額外的精力。
  5. 多精度算術可以利用MMX集合和類似集合提供的矢量運算。

簡而言之,這些小奇跡如此昂貴是有原因的:)

首先,正如已經指出的,time()輸出實際上以秒為單位,而不是毫秒。

另外,您實際上是對總共1m ** 2/2執行1m次加法,不算到1m,並且您正在初始化一個帶有range一百萬個長的列表(除非您在python 3上)。

我在筆記本電腦上進行了一個更簡單的測試:

start = time.time()
i = 0;
while i < 1000000:
   i+=1
print time.time() - start

結果:

0.069179093451

因此,為70毫秒。 這意味着每秒可進行1400 萬次操作。

讓我們看一下Stefano可能引用的表( http://en.wikipedia.org/wiki/Instructions_per_second )並進行粗略估計。 他們沒有像我一樣的i5,但是最慢的i7足夠接近。 它具有4個內核的80 GIPS時鍾,每個內核20 GIPS。

(順便說一句,如果您的問題是“如何使每個內核獲得20 GIPS?”,這 無濟於事 。這是 maaaagic 納米技術)

因此,該內核每秒能夠進行200 億次操作,而我們得到的1400 萬次差異僅為1400倍。

此時,正確的問題不是“為什么這么快?”,不是“ 為什么這么慢? ”。 可能是python開銷。 如果我們在C中嘗試該怎么辦?

#include <stdio.h>
#include <unistd.h>
#include <time.h>

int i = 0;
int million = 1000000;
int main() {

    clock_t cstart = clock();
    while (i < million) {
     i += 1;
    }

    clock_t cend = clock();
    printf ("%.3f cpu sec\n", ((double)cend - (double)cstart) / CLOCKS_PER_SEC);
    return 0;
}

結果:

0.003 cpu sec

它比python快23倍,與每秒理論“基本操作”的數量僅相差60倍。 我在這里看到兩個操作-比較和加法,所以相差30倍。 這是完全合理的,因為基本操作可能比我們的加法和比較小得多(讓匯編專家告訴我們),而且我們也沒有考慮上下文切換,緩存未命中,時間計算開銷以及誰知道其他什么。

這也表明python執行相同操作的操作量是23倍。 這也是完全合理的,因為python是一種高級語言。 這是高級語言中的一種懲罰-現在您了解了為什么速度至關重要的部分通常用C編寫。

另外,python的整數是不可變的,應該為每個新的整數分配內存(python運行時對此很聰明,不過)。

我希望能回答您的問題,並教給您一些有關如何執行令人難以置信的粗略估計=)

簡短答案:正如jonrsharpe在評論中提到的,這是秒,而不是毫秒。

也正如Stefano所說,xxxxxx->檢查他發布的答案。 除了ALU之外,它還有很多細節。

我只是想提一提-當您在類或函數中設置默認值時,請確保使用簡單的不可變而不是進行函數調用或類似的操作。 您的課程實際上是在為所有實例設置計時器的開始時間-如果創建新的Timer,您會感到非常驚訝,因為它將使用以前的值作為初始值。 嘗試此操作,第二個Timer不會重置Timer

#...
count = 0
Timer = StopWatch()
time.sleep(1)
Timer - StopWatch()
for i in range(1, 1000001):
    count += i
Timer.stop()
total_Time = Timer.getElapsedTime()
print("Total time elapsed to count to 1,000,000: ",total_Time," milliseconds")

您將得到大約1秒的時間,而不是您期望的時間。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM