[英]Python3.3: Square-root optimization
這是Python3.3上的代碼:
import sys, re, math
str1 = str(sys.stdin.readlines())
Data = re.findall('\\b\\d+\\b', str1)
for i in reversed (Data):
print('%.4f' % math.sqrt(float(i)))
如您所見,該程序從輸入中獲取數據(多行隨機字符串),並搜索該字符串包含的每個數字。 之后,僅返回找到的每個數字的平方根。
好吧,算法有效,但速度不夠快,我也不知道如何優化它。 請幫我。 我需要做些什么來優化上面的代碼?
這是負面的結果。 我嘗試使用一些技巧來使它更快,但是只是快了一點。
import sys, re, math
def find_numbers(f):
for line in f:
for word in line.split():
if word.isdigit():
yield float(word)
lst = list(find_numbers(sys.stdin))
lst.reverse()
for x in lst:
print('%.4f' % math.sqrt(x))
我以為反轉列表可能會使它變慢,但是當我只打印數字而不反轉時,並沒有太大的區別。
Python最快的解決方案是僅在PyPy中運行以上代碼。
這不是一個非常困難的問題,如果需要提高速度,則可能需要用C代碼編寫解決方案。 對於此問題,C代碼將以最快的速度獲得。
您可以嘗試使用Numpy加載和處理文件:
import numpy as np
for i in reversed(np.fromfile(sys.stdin, sep=' ')**0.5):
print i
作為Python的高性能數字庫,我希望它是為您提供的最快的解決方案。
您要求使用Python,但這在C語言中可以很好地完成。此C程序不會反轉數字,但是您可以通過tac
程序簡單地將輸出通過管道傳輸,就像cat
一樣,但可以反轉行。
在我的測試中,這大約是NumPy解決方案速度的3倍,是我的Python解決方案或原始解決方案速度的6倍。
#include <ctype.h>
#include <math.h>
#include <stdio.h>
int
main()
{
char buf[1024];
char ch;
float f;
int i, n;
for (i = 0;;)
{
ch = getchar();
if (i > sizeof(buf))
{
fprintf(stderr, "number too long!\n");
return 1;
}
if (isspace(ch) || EOF == ch)
{
if (i > 0)
{
buf[i] = '\0';
n = atoi(buf);
f = sqrtf(n);
printf("%0.4f\n", f);
i = 0;
}
if (EOF == ch)
return 0;
continue;
}
buf[i++] = ch;
}
}
更新:抱歉,發布了Steveha的更早答案的副本。 談到我的閱讀技巧。 只是由於我對I / O /緩沖/運行時效果的困惑,目前仍在線上保留此答案。
原始帖子:
我不敢相信Python應用一個正則表達式並計算一個平方根所花的時間要比從標准輸入中讀取一行並在標准輸出(或任何I / O)上輸出結果所花費的時間更長。
由於某個時間點的I / O來自一個硬盤驅動器,並且將轉到另一個硬盤驅動器或用戶的視線,因此這應該是限制因素。
I / O通常被緩沖以加快速度。 通常,緩沖區中填充有突發數據,然后CPU在等待設備提供更多數據時處於空閑狀態。
這會為您的應用程序生成一個生成器。 編寫一個生成器,逐行讀取輸入,並根據需要立即提供sqrt編號。 我懷疑這會不會比任何合理的現代硬件上的總體I / O速度慢。 如果您使用的是特殊設備(例如嵌入式,uController,Raspberry Pi等,請告知我們)
您可以做的一種優化是預編譯正則表達式。 由於每個測試都使用相同的正則表達式,因此讓我們僅對正則表達式進行一次解析。 這個問題中的示例很好,因為您正在執行re.findall()
。 我只是在為其他讀者准備。
import sys, re, math
pattern = re.compile(r'\b\d+\b')
def fh_numbers_to_sqrt(fh):
for line in fh:
for i in re.findall(pattern, line):
yield math.sqrt(float(i))
numbers_g = fh_numbers_to_sqrt(sys.stdin)
for num in numbers_g:
print('%.4f' % num)
這允許所有的正則表達式和數學運算與I / O時間交錯。
現在,我們根本無法真正優化和集成的一件事是reverse
。 該算法必須等到最后一個元素才能反轉。
因此,我們可以將調用代碼更改為:
numbers_g = fh_numbers_to_sqrt(sys.stdin)
for num in reverse(list(numbers_g)):
print('%.4f' % num)
並希望這比您原先的速度更快。 同樣,這樣做速度更快的唯一原因是因為我們在從標准輸入讀取數據所需的掛鍾時間內,隱藏了正則表達式解析和計算的運行時間。 這應該仍然受I / O限制。 實際上, reverse
可能並不會真正增加總體運行時間,因為它可能與標准輸出上發生的I / O發生交錯。 看着牆上的時鍾,此算法可能根本沒有時間用完。 :-)
為了證明或否定我的整個帖子,您可以使用time.time()
來衡量從腳本開始到Data = re.findall
行之前以及之后到結束之間所Data = re.findall
時間。 如果我是正確的,那么數據讀取將花費大部分時間。 如果不是,則值得測量所有正則表達式搜索所需的時間。 讓我們知道 我很好奇...
import sys, re, math
str1 = str(sys.stdin.readlines())
Data = re.findall('\\b\\d+\\b', str1)
d2 = [round(math.sqrt(float(i)),4) for i in reversed (Data)]
for i in d2:
print(i)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.