작은 목록보다 작은 문자열에 대해 반복하는 것이 느린 이유는 무엇입니까?
저는 그것을 가지고 놀다가 작은 문자열에 대한 간단한 목록 이해를 하는 것이 작은 단일 문자열 목록에서 같은 작업을 하는 것보다 더 오래 걸린다는 것을 깨달았습니다.무슨 설명이라도?그것은 거의 1.35배의 시간입니다.
>>> from timeit import timeit
>>> timeit("[x for x in 'abc']")
2.0691067844831528
>>> timeit("[x for x in ['a', 'b', 'c']]")
1.5286479570345861
더 낮은 단계에서 무슨 일이 일어나고 있으며 이로 인해 발생하는 것입니까?
TL;DR
Python 2의 경우 오버헤드가 많이 제거되면 실제 속도 차이는 70%(또는 그 이상)에 가깝습니다.
개체 생성에 문제가 없습니다.한 문자 문자열이 캐시되므로 두 메서드 모두 새 개체를 만들지 않습니다.
이 차이는 눈에 띄지 않지만 유형 및 올바른 형식과 관련하여 문자열 인덱싱에 대한 더 많은 검사에서 발생할 수 있습니다.그것은 또한 무엇을 반환해야 하는지 확인할 필요성 때문일 가능성이 높습니다.
목록 인덱싱 속도가 매우 빠릅니다.
>>> python3 -m timeit '[x for x in "abc"]'
1000000 loops, best of 3: 0.388 usec per loop
>>> python3 -m timeit '[x for x in ["a", "b", "c"]]'
1000000 loops, best of 3: 0.436 usec per loop
이것은 당신이 발견한 것과 일치하지 않습니다...
그렇다면 당신은 파이썬 2를 사용하고 있는 것이 틀림없습니다.
>>> python2 -m timeit '[x for x in "abc"]'
1000000 loops, best of 3: 0.309 usec per loop
>>> python2 -m timeit '[x for x in ["a", "b", "c"]]'
1000000 loops, best of 3: 0.212 usec per loop
버전 간의 차이점을 설명하겠습니다.컴파일된 코드를 검토하겠습니다.
Python 3의 경우:
import dis
def list_iterate():
[item for item in ["a", "b", "c"]]
dis.dis(list_iterate)
#>>> 4 0 LOAD_CONST 1 (<code object <listcomp> at 0x7f4d06b118a0, file "", line 4>)
#>>> 3 LOAD_CONST 2 ('list_iterate.<locals>.<listcomp>')
#>>> 6 MAKE_FUNCTION 0
#>>> 9 LOAD_CONST 3 ('a')
#>>> 12 LOAD_CONST 4 ('b')
#>>> 15 LOAD_CONST 5 ('c')
#>>> 18 BUILD_LIST 3
#>>> 21 GET_ITER
#>>> 22 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
#>>> 25 POP_TOP
#>>> 26 LOAD_CONST 0 (None)
#>>> 29 RETURN_VALUE
def string_iterate():
[item for item in "abc"]
dis.dis(string_iterate)
#>>> 21 0 LOAD_CONST 1 (<code object <listcomp> at 0x7f4d06b17150, file "", line 21>)
#>>> 3 LOAD_CONST 2 ('string_iterate.<locals>.<listcomp>')
#>>> 6 MAKE_FUNCTION 0
#>>> 9 LOAD_CONST 3 ('abc')
#>>> 12 GET_ITER
#>>> 13 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
#>>> 16 POP_TOP
#>>> 17 LOAD_CONST 0 (None)
#>>> 20 RETURN_VALUE
목록을 작성할 때마다 목록 변형 속도가 느려지는 것을 볼 수 있습니다.
여기가 바로
9 LOAD_CONST 3 ('a')
12 LOAD_CONST 4 ('b')
15 LOAD_CONST 5 ('c')
18 BUILD_LIST 3
part. 문자열 변형은 다음을 포함합니다.
9 LOAD_CONST 3 ('abc')
이를 통해 차이가 있는지 확인할 수 있습니다.
def string_iterate():
[item for item in ("a", "b", "c")]
dis.dis(string_iterate)
#>>> 35 0 LOAD_CONST 1 (<code object <listcomp> at 0x7f4d068be660, file "", line 35>)
#>>> 3 LOAD_CONST 2 ('string_iterate.<locals>.<listcomp>')
#>>> 6 MAKE_FUNCTION 0
#>>> 9 LOAD_CONST 6 (('a', 'b', 'c'))
#>>> 12 GET_ITER
#>>> 13 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
#>>> 16 POP_TOP
#>>> 17 LOAD_CONST 0 (None)
#>>> 20 RETURN_VALUE
이것은 정당한 결과를 낳습니다.
9 LOAD_CONST 6 (('a', 'b', 'c'))
불변의 예법테스트:
>>> python3 -m timeit '[x for x in ("a", "b", "c")]'
1000000 loops, best of 3: 0.369 usec per loop
좋아요, 속도를 내세요.
Python 2의 경우:
def list_iterate():
[item for item in ["a", "b", "c"]]
dis.dis(list_iterate)
#>>> 2 0 BUILD_LIST 0
#>>> 3 LOAD_CONST 1 ('a')
#>>> 6 LOAD_CONST 2 ('b')
#>>> 9 LOAD_CONST 3 ('c')
#>>> 12 BUILD_LIST 3
#>>> 15 GET_ITER
#>>> >> 16 FOR_ITER 12 (to 31)
#>>> 19 STORE_FAST 0 (item)
#>>> 22 LOAD_FAST 0 (item)
#>>> 25 LIST_APPEND 2
#>>> 28 JUMP_ABSOLUTE 16
#>>> >> 31 POP_TOP
#>>> 32 LOAD_CONST 0 (None)
#>>> 35 RETURN_VALUE
def string_iterate():
[item for item in "abc"]
dis.dis(string_iterate)
#>>> 2 0 BUILD_LIST 0
#>>> 3 LOAD_CONST 1 ('abc')
#>>> 6 GET_ITER
#>>> >> 7 FOR_ITER 12 (to 22)
#>>> 10 STORE_FAST 0 (item)
#>>> 13 LOAD_FAST 0 (item)
#>>> 16 LIST_APPEND 2
#>>> 19 JUMP_ABSOLUTE 7
#>>> >> 22 POP_TOP
#>>> 23 LOAD_CONST 0 (None)
#>>> 26 RETURN_VALUE
이상한 것은 우리가 목록의 같은 건물을 가지고 있다는 것입니다. 하지만 이것은 여전히 더 빠릅니다.Python 2는 이상하게 빠르게 동작합니다.
이해관계를 제거하고 시간을 재설정합니다._ =
최적화되는 것을 방지하는 것입니다.
>>> python3 -m timeit '_ = ["a", "b", "c"]'
10000000 loops, best of 3: 0.0707 usec per loop
>>> python3 -m timeit '_ = "abc"'
100000000 loops, best of 3: 0.0171 usec per loop
초기화가 버전 간의 차이를 설명할 만큼 충분히 중요하지 않다는 것을 알 수 있습니다(이러한 숫자는 작습니다).따라서 Python 3의 이해가 더 느리다는 결론을 내릴 수 있습니다.이것은 Python 3이 더 안전한 범위 지정을 위해 이해 범위를 변경했기 때문에 의미가 있습니다.
이제 벤치마크를 개선합니다(반복되지 않는 오버헤드를 제거하는 것 뿐입니다).그러면 다음과 같이 미리 할당하여 반복 가능한 건물이 제거됩니다.
>>> python3 -m timeit -s 'iterable = "abc"' '[x for x in iterable]'
1000000 loops, best of 3: 0.387 usec per loop
>>> python3 -m timeit -s 'iterable = ["a", "b", "c"]' '[x for x in iterable]'
1000000 loops, best of 3: 0.368 usec per loop
>>> python2 -m timeit -s 'iterable = "abc"' '[x for x in iterable]'
1000000 loops, best of 3: 0.309 usec per loop
>>> python2 -m timeit -s 'iterable = ["a", "b", "c"]' '[x for x in iterable]'
10000000 loops, best of 3: 0.164 usec per loop
우리는 전화를 했는지 확인할 수 있습니다.iter
오버헤드:
>>> python3 -m timeit -s 'iterable = "abc"' 'iter(iterable)'
10000000 loops, best of 3: 0.099 usec per loop
>>> python3 -m timeit -s 'iterable = ["a", "b", "c"]' 'iter(iterable)'
10000000 loops, best of 3: 0.1 usec per loop
>>> python2 -m timeit -s 'iterable = "abc"' 'iter(iterable)'
10000000 loops, best of 3: 0.0913 usec per loop
>>> python2 -m timeit -s 'iterable = ["a", "b", "c"]' 'iter(iterable)'
10000000 loops, best of 3: 0.0854 usec per loop
아니요, 아닙니다특히 Python 3의 경우 차이가 너무 작습니다.
그래서 불필요한 오버헤드를 제거해 봅시다.모든 것을 느리게 함으로써!목적은 시간이 오버헤드를 숨기도록 반복이 더 길어지는 것입니다.
>>> python3 -m timeit -s 'import random; iterable = "".join(chr(random.randint(0, 127)) for _ in range(100000))' '[x for x in iterable]'
100 loops, best of 3: 3.12 msec per loop
>>> python3 -m timeit -s 'import random; iterable = [chr(random.randint(0, 127)) for _ in range(100000)]' '[x for x in iterable]'
100 loops, best of 3: 2.77 msec per loop
>>> python2 -m timeit -s 'import random; iterable = "".join(chr(random.randint(0, 127)) for _ in range(100000))' '[x for x in iterable]'
100 loops, best of 3: 2.32 msec per loop
>>> python2 -m timeit -s 'import random; iterable = [chr(random.randint(0, 127)) for _ in range(100000)]' '[x for x in iterable]'
100 loops, best of 3: 2.09 msec per loop
이것은 실제로 많이 변하지는 않았지만, 조금 도움이 되었습니다.
그러니까 이해력을 제거하세요.질문의 일부가 아닌 간접비입니다.
>>> python3 -m timeit -s 'import random; iterable = "".join(chr(random.randint(0, 127)) for _ in range(100000))' 'for x in iterable: pass'
1000 loops, best of 3: 1.71 msec per loop
>>> python3 -m timeit -s 'import random; iterable = [chr(random.randint(0, 127)) for _ in range(100000)]' 'for x in iterable: pass'
1000 loops, best of 3: 1.36 msec per loop
>>> python2 -m timeit -s 'import random; iterable = "".join(chr(random.randint(0, 127)) for _ in range(100000))' 'for x in iterable: pass'
1000 loops, best of 3: 1.27 msec per loop
>>> python2 -m timeit -s 'import random; iterable = [chr(random.randint(0, 127)) for _ in range(100000)]' 'for x in iterable: pass'
1000 loops, best of 3: 935 usec per loop
그게 더 좋아요!를 사용하면 조금 더 빨라질 수 있습니다.deque
반복해서기본적으로 동일하지만 속도가 더 빠릅니다.
>>> python3 -m timeit -s 'import random; from collections import deque; iterable = "".join(chr(random.randint(0, 127)) for _ in range(100000))' 'deque(iterable, maxlen=0)'
1000 loops, best of 3: 777 usec per loop
>>> python3 -m timeit -s 'import random; from collections import deque; iterable = [chr(random.randint(0, 127)) for _ in range(100000)]' 'deque(iterable, maxlen=0)'
1000 loops, best of 3: 405 usec per loop
>>> python2 -m timeit -s 'import random; from collections import deque; iterable = "".join(chr(random.randint(0, 127)) for _ in range(100000))' 'deque(iterable, maxlen=0)'
1000 loops, best of 3: 805 usec per loop
>>> python2 -m timeit -s 'import random; from collections import deque; iterable = [chr(random.randint(0, 127)) for _ in range(100000)]' 'deque(iterable, maxlen=0)'
1000 loops, best of 3: 438 usec per loop
제가 인상 깊었던 것은 유니코드가 테스트링에 의해 경쟁력이 있다는 것입니다.우리는 시도함으로써 이것을 명시적으로 확인할 수 있습니다.bytes
그리고.unicode
다 다 둘:
bytes
>>> python3 -m timeit -s 'import random; from collections import deque; iterable = b"".join(chr(random.randint(0, 127)).encode("ascii") for _ in range(100000))' 'deque(iterable, maxlen=0)' :( 1000 loops, best of 3: 571 usec per loop >>> python3 -m timeit -s 'import random; from collections import deque; iterable = [chr(random.randint(0, 127)).encode("ascii") for _ in range(100000)]' 'deque(iterable, maxlen=0)' 1000 loops, best of 3: 394 usec per loop
>>> python2 -m timeit -s 'import random; from collections import deque; iterable = b"".join(chr(random.randint(0, 127)) for _ in range(100000))' 'deque(iterable, maxlen=0)' 1000 loops, best of 3: 757 usec per loop >>> python2 -m timeit -s 'import random; from collections import deque; iterable = [chr(random.randint(0, 127)) for _ in range(100000)]' 'deque(iterable, maxlen=0)' 1000 loops, best of 3: 438 usec per loop
여기 파이썬 3이 파이썬 2보다 실제로 더 빠릅니다.
unicode
>>> python3 -m timeit -s 'import random; from collections import deque; iterable = u"".join( chr(random.randint(0, 127)) for _ in range(100000))' 'deque(iterable, maxlen=0)' 1000 loops, best of 3: 800 usec per loop >>> python3 -m timeit -s 'import random; from collections import deque; iterable = [ chr(random.randint(0, 127)) for _ in range(100000)]' 'deque(iterable, maxlen=0)' 1000 loops, best of 3: 394 usec per loop
>>> python2 -m timeit -s 'import random; from collections import deque; iterable = u"".join(unichr(random.randint(0, 127)) for _ in range(100000))' 'deque(iterable, maxlen=0)' 1000 loops, best of 3: 1.07 msec per loop >>> python2 -m timeit -s 'import random; from collections import deque; iterable = [unichr(random.randint(0, 127)) for _ in range(100000)]' 'deque(iterable, maxlen=0)' 1000 loops, best of 3: 469 usec per loop
입니다. (Python 3, Python 3)
str
Python 3)에서 많은 관심을 받았습니다.
이 사실, 은것이.unicode
-bytes
차이가 매우 작으며, 이것은 인상적입니다.
이제 한 가지 사례를 분석해 보겠습니다. 빠르고 편리하기 때문입니다.
>>> python3 -m timeit -s 'import random; from collections import deque; iterable = "".join(chr(random.randint(0, 127)) for _ in range(100000))' 'deque(iterable, maxlen=0)'
1000 loops, best of 3: 777 usec per loop
>>> python3 -m timeit -s 'import random; from collections import deque; iterable = [chr(random.randint(0, 127)) for _ in range(100000)]' 'deque(iterable, maxlen=0)'
1000 loops, best of 3: 405 usec per loop
우리는 실제로 팀 피터의 10배 투표된 대답을 배제할 수 있습니다!
>>> foo = iterable[123]
>>> iterable[36] is foo
True
이것들은 새로운 물체가 아닙니다!
하지만 이것은 언급할 가치가 있습니다: 인덱싱 비용.인덱스에 차이가 있을 수 있으므로 반복을 제거하고 인덱스만 사용합니다.
>>> python3 -m timeit -s 'import random; iterable = "".join(chr(random.randint(0, 127)) for _ in range(100000))' 'iterable[123]'
10000000 loops, best of 3: 0.0397 usec per loop
>>> python3 -m timeit -s 'import random; iterable = [chr(random.randint(0, 127)) for _ in range(100000)]' 'iterable[123]'
10000000 loops, best of 3: 0.0374 usec per loop
차이는 작아 보이지만 비용의 절반 이상이 간접비입니다.
>>> python3 -m timeit -s 'import random; iterable = [chr(random.randint(0, 127)) for _ in range(100000)]' 'iterable; 123'
100000000 loops, best of 3: 0.0173 usec per loop
그래서 속도 차이는 그것을 비난하기로 결정하기에 충분합니다.생각합니다.
그렇다면 왜 목록을 인덱싱하는 것이 훨씬 빠를까요?
음, 다시 말씀드리지만, 제 생각에는 그것은 인터내팅된 문자열(또는 별도의 메커니즘인 경우 캐시된 문자)에 대한 검사에 달려 있습니다.이 속도는 최적 속도보다 빠릅니다.하지만 출처는 제가 확인해보겠습니다(C...) :).
출처는 다음과 같습니다.
static PyObject *
unicode_getitem(PyObject *self, Py_ssize_t index)
{
void *data;
enum PyUnicode_Kind kind;
Py_UCS4 ch;
PyObject *res;
if (!PyUnicode_Check(self) || PyUnicode_READY(self) == -1) {
PyErr_BadArgument();
return NULL;
}
if (index < 0 || index >= PyUnicode_GET_LENGTH(self)) {
PyErr_SetString(PyExc_IndexError, "string index out of range");
return NULL;
}
kind = PyUnicode_KIND(self);
data = PyUnicode_DATA(self);
ch = PyUnicode_READ(kind, data, index);
if (ch < 256)
return get_latin1_char(ch);
res = PyUnicode_New(1, ch);
if (res == NULL)
return NULL;
kind = PyUnicode_KIND(res);
data = PyUnicode_DATA(res);
PyUnicode_WRITE(kind, data, 0, ch);
assert(_PyUnicode_CheckConsistency(res, 1));
return res;
}
위에서 걸어가면, 우리는 몇 가지 점검을 받을 것입니다.이것들은 지루합니다.그러면 어떤 사람들은 할당하는데, 이것 또한 지루할 것입니다.첫번째 흥미로운 대사는
ch = PyUnicode_READ(kind, data, index);
하지만 색인화를 통해 연속적인 C 배열을 읽고 있기 때문에 속도가 빠르기를 바랍니다.결과는,ch
256보다 작으므로 캐시된 문자를 에 반환합니다.get_latin1_char(ch)
.
그래서 우리는 실행할 것입니다 (첫 번째 검사를 삭제합니다).
kind = PyUnicode_KIND(self);
data = PyUnicode_DATA(self);
ch = PyUnicode_READ(kind, data, index);
return get_latin1_char(ch);
어디에
#define PyUnicode_KIND(op) \
(assert(PyUnicode_Check(op)), \
assert(PyUnicode_IS_READY(op)), \
((PyASCIIObject *)(op))->state.kind)
debug [할 수 asserts에서 무시되기 .((PyASCIIObject *)(op))->state.kind)
생각에는) 캐스트야 (C급 캐스트야) C급 캐스트야.
#define PyUnicode_DATA(op) \
(assert(PyUnicode_Check(op)), \
PyUnicode_IS_COMPACT(op) ? _PyUnicode_COMPACT_DATA(op) : \
_PyUnicode_NONCOMPACT_DATA(op))
.)Something_CAPITALIZED
모두 빠름),
#define PyUnicode_READ(kind, data, index) \
((Py_UCS4) \
((kind) == PyUnicode_1BYTE_KIND ? \
((const Py_UCS1 *)(data))[(index)] : \
((kind) == PyUnicode_2BYTE_KIND ? \
((const Py_UCS2 *)(data))[(index)] : \
((const Py_UCS4 *)(data))[(index)] \
) \
))
(인덱스를 포함하지만 전혀 느리지 않습니다.)
static PyObject*
get_latin1_char(unsigned char ch)
{
PyObject *unicode = unicode_latin1[ch];
if (!unicode) {
unicode = PyUnicode_New(1, ch);
if (!unicode)
return NULL;
PyUnicode_1BYTE_DATA(unicode)[0] = ch;
assert(_PyUnicode_CheckConsistency(unicode, 1));
unicode_latin1[ch] = unicode;
}
Py_INCREF(unicode);
return unicode;
}
제 의심을 확인시켜 주는군요
캐시됨:
PyObject *unicode = unicode_latin1[ch];
이거 빨라야 돼요. 그.
if (!unicode)
실행되지 않으므로 이 경우 문자 그대로 다음과 같습니다.PyObject *unicode = unicode_latin1[ch]; Py_INCREF(unicode); return unicode;
솔직히, 테스트 후에.assert
s는 빠릅니다([C-level asserts에서 작동하는 것 같습니다...]). 유일하게 느린 부분은 다음과 같습니다.
PyUnicode_IS_COMPACT(op)
_PyUnicode_COMPACT_DATA(op)
_PyUnicode_NONCOMPACT_DATA(op)
다음 항목:
#define PyUnicode_IS_COMPACT(op) \
(((PyASCIIObject*)(op))->state.compact)
(빠른 속도로, 이전처럼)
#define _PyUnicode_COMPACT_DATA(op) \
(PyUnicode_IS_ASCII(op) ? \
((void*)((PyASCIIObject*)(op) + 1)) : \
((void*)((PyCompactUnicodeObject*)(op) + 1)))
(매크로가 빠른 경우)IS_ASCII
빠름) 및
#define _PyUnicode_NONCOMPACT_DATA(op) \
(assert(((PyUnicodeObject*)(op))->data.any), \
((((PyUnicodeObject *)(op))->data.any)))
(또한 아사트 + 간접 + 출연진이기 때문에 빠릅니다.)
그래서 우리는 (토끼 구멍) 아래에 있습니다:
PyUnicode_IS_ASCII
어느 것이
#define PyUnicode_IS_ASCII(op) \
(assert(PyUnicode_Check(op)), \
assert(PyUnicode_IS_READY(op)), \
((PyASCIIObject*)op)->state.ascii)
음... 너무 빠른 것 같은데요...
좋아요, 하지만 그것을 비교해 봅시다.PyList_GetItem
(네, 팀 피터스가 저에게 더 많은 일을 주셔서 감사합니다:P.)
PyObject *
PyList_GetItem(PyObject *op, Py_ssize_t i)
{
if (!PyList_Check(op)) {
PyErr_BadInternalCall();
return NULL;
}
if (i < 0 || i >= Py_SIZE(op)) {
if (indexerr == NULL) {
indexerr = PyUnicode_FromString(
"list index out of range");
if (indexerr == NULL)
return NULL;
}
PyErr_SetObject(PyExc_IndexError, indexerr);
return NULL;
}
return ((PyListObject *)op) -> ob_item[i];
}
오류가 없는 경우에는 다음과 같이 실행됩니다.
PyList_Check(op)
Py_SIZE(op)
((PyListObject *)op) -> ob_item[i]
어디에PyList_Check
이라
#define PyList_Check(op) \
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_LIST_SUBCLASS)
(
탭! 탭!!!) ( 87호) 5분 만에 수정되고 통합되었습니다.마치...네, 젠장그들은 스키트를 부끄럽게 했습니다.
#define Py_SIZE(ob) (((PyVarObject*)(ob))->ob_size)
#define PyType_FastSubclass(t,f) PyType_HasFeature(t,f)
#ifdef Py_LIMITED_API
#define PyType_HasFeature(t,f) ((PyType_GetFlags(t) & (f)) != 0)
#else
#define PyType_HasFeature(t,f) (((t)->tp_flags & (f)) != 0)
#endif
따라서 이것은 일반적으로 매우 사소한 것입니다. (두 개의 지시문과 두 개의 부울 검사) 다음을 제외하고는Py_LIMITED_API
켜져 있어요, 어떤 경우에... ???
그리고 인덱싱과 캐스트가 있습니다.((PyListObject *)op) -> ob_item[i]
) 그리고 우리는 끝입니다.
따라서 목록에 대한 검사가 확실히 적으며, 속도 차이가 작다는 것은 관련성이 있을 수 있다는 것을 의미합니다.
제 생각에는 일반적으로 유형 확인과 방향성이 더 있을 뿐입니다.(->)
유니코드의 경우.제가 요점을 놓치고 있는 것 같습니다만, 뭐라고요?
대부분의 컨테이너 개체(목록, 튜플, 딕트 등)를 반복하면 반복기가 컨테이너에 있는 개체를 전달합니다.
그러나 문자열을 반복할 때는 전달된 각 문자에 대해 새 개체를 만들어야 합니다. 문자열은 목록이 컨테이너인 것과 같은 의미에서 "컨테이너"가 아닙니다.문자열의 개별 문자는 해당 개체를 반복적으로 만들기 전에 별개의 개체로 존재하지 않습니다.
문자열에 대한 반복기를 만드는 데 드는 비용과 오버헤드가 발생할 수 있습니다.반면, 어레이에는 이미 인스턴스화 시 반복기가 포함되어 있습니다.
편집:
>>> timeit("[x for x in ['a','b','c']]")
0.3818681240081787
>>> timeit("[x for x in 'abc']")
0.3732869625091553
이것은 2.7을 사용하여 실행되었지만, 제 맥북 프로7에서 실행되었습니다.이는 시스템 구성 차이의 결과일 수 있습니다.
언급URL : https://stackoverflow.com/questions/23861468/why-is-it-slower-to-iterate-over-a-small-string-than-a-small-list
'programing' 카테고리의 다른 글
Django 템플릿의 계수 % (0) | 2023.08.05 |
---|---|
스위프트에서 문자열을 부동으로 변환 (0) | 2023.08.05 |
요청한 항목을 찾을 수 없습니다.Visual Studio 2010 Professional의 Net Framework 데이터 공급자 (0) | 2023.08.05 |
jquery를 tampermonkey 스크립트에 로드하려고 합니다. (0) | 2023.08.05 |
HTML 테이블의 데이터 테이블 (0) | 2023.08.05 |