이를위한 Pythonic 방법은 다음과 같습니다.
x = [None] * numElements
또는 미리 채울 기본값, 예를 들어
bottles = [Beer()] * 99
sea = [Fish()] * many
vegetarianPizzas = [None] * peopleOrderingPizzaNotQuiche
[편집 : emptor 경고 의 [Beer()] * 99
구문 생성 한 Beer
후, 동일한 단일 인스턴스 99 참조 배열을 채우는]
파이썬의 기본 접근 방식은 요소 수를 늘리면 효율성이 떨어지지 만 상당히 효율적 일 수 있습니다.
비교
import time
class Timer(object):
def __enter__(self):
self.start = time.time()
return self
def __exit__(self, *args):
end = time.time()
secs = end - self.start
msecs = secs * 1000 # millisecs
print('%fms' % msecs)
Elements = 100000
Iterations = 144
print('Elements: %d, Iterations: %d' % (Elements, Iterations))
def doAppend():
result = []
i = 0
while i < Elements:
result.append(i)
i += 1
def doAllocate():
result = [None] * Elements
i = 0
while i < Elements:
result[i] = i
i += 1
def doGenerator():
return list(i for i in range(Elements))
def test(name, fn):
print("%s: " % name, end="")
with Timer() as t:
x = 0
while x < Iterations:
fn()
x += 1
test('doAppend', doAppend)
test('doAllocate', doAllocate)
test('doGenerator', doGenerator)
와
#include <vector>
typedef std::vector<unsigned int> Vec;
static const unsigned int Elements = 100000;
static const unsigned int Iterations = 144;
void doAppend()
{
Vec v;
for (unsigned int i = 0; i < Elements; ++i) {
v.push_back(i);
}
}
void doReserve()
{
Vec v;
v.reserve(Elements);
for (unsigned int i = 0; i < Elements; ++i) {
v.push_back(i);
}
}
void doAllocate()
{
Vec v;
v.resize(Elements);
for (unsigned int i = 0; i < Elements; ++i) {
v[i] = i;
}
}
#include <iostream>
#include <chrono>
using namespace std;
void test(const char* name, void(*fn)(void))
{
cout << name << ": ";
auto start = chrono::high_resolution_clock::now();
for (unsigned int i = 0; i < Iterations; ++i) {
fn();
}
auto end = chrono::high_resolution_clock::now();
auto elapsed = end - start;
cout << chrono::duration<double, milli>(elapsed).count() << "ms\n";
}
int main()
{
cout << "Elements: " << Elements << ", Iterations: " << Iterations << '\n';
test("doAppend", doAppend);
test("doReserve", doReserve);
test("doAllocate", doAllocate);
}
내 Windows 7 i7에서 64 비트 Python이
Elements: 100000, Iterations: 144
doAppend: 3587.204933ms
doAllocate: 2701.154947ms
doGenerator: 1721.098185ms
C ++이 제공하는 동안 (MSVC, 64 비트, 최적화 사용)
Elements: 100000, Iterations: 144
doAppend: 74.0042ms
doReserve: 27.0015ms
doAllocate: 5.0003ms
C ++ 디버그 빌드는 다음을 생성합니다.
Elements: 100000, Iterations: 144
doAppend: 2166.12ms
doReserve: 2082.12ms
doAllocate: 273.016ms
여기서 중요한 점은 파이썬을 사용하면 7-8 %의 성능 향상을 달성 할 수 있으며, 고성능 앱을 작성한다고 생각하거나 웹 서비스 또는 무언가에 사용되는 것을 작성한다고 생각되면 스니핑되지는 않지만 언어 선택을 다시 생각해야 할 수도 있습니다.
또한 여기의 파이썬 코드는 실제로 파이썬 코드가 아닙니다. 진정한 Pythonesque 코드로 전환하면 성능이 향상됩니다.
import time
class Timer(object):
def __enter__(self):
self.start = time.time()
return self
def __exit__(self, *args):
end = time.time()
secs = end - self.start
msecs = secs * 1000 # millisecs
print('%fms' % msecs)
Elements = 100000
Iterations = 144
print('Elements: %d, Iterations: %d' % (Elements, Iterations))
def doAppend():
for x in range(Iterations):
result = []
for i in range(Elements):
result.append(i)
def doAllocate():
for x in range(Iterations):
result = [None] * Elements
for i in range(Elements):
result[i] = i
def doGenerator():
for x in range(Iterations):
result = list(i for i in range(Elements))
def test(name, fn):
print("%s: " % name, end="")
with Timer() as t:
fn()
test('doAppend', doAppend)
test('doAllocate', doAllocate)
test('doGenerator', doGenerator)
어느 것이
Elements: 100000, Iterations: 144
doAppend: 2153.122902ms
doAllocate: 1346.076965ms
doGenerator: 1614.092112ms
32 비트 doGenerator는 doAllocate보다 낫습니다.
여기서 doAppend와 doAllocate의 간격이 상당히 큽니다.
분명히 여기의 차이점은 소수 이상의 작업을 수행하거나로드가 많은 시스템에서이 작업을 수행하는 경우에만 적용됩니다. 상당히 큰 목록.
요점은 다음과 같습니다. 최고의 성능을 얻으려면 pythonic 방식으로하십시오.
그러나 일반적인 높은 수준의 성능에 대해 걱정한다면 Python은 잘못된 언어입니다. 가장 근본적인 문제는 Python 함수 호출이 데코레이터 등과 같은 Python 기능으로 인해 전통적으로 다른 언어보다 최대 300 배 느리다는 것입니다 ( https://wiki.python.org/moin/PythonSpeed/PerformanceTips#Data_Aggregation#Data_Aggregation ).