উপাদানগুলি ইনস্ট্যান্টেশন এবং পুনরুদ্ধারের ক্ষেত্রে টিপলস এবং তালিকার মধ্যে কোনও পারফরম্যান্সের পার্থক্য রয়েছে কি?
উপাদানগুলি ইনস্ট্যান্টেশন এবং পুনরুদ্ধারের ক্ষেত্রে টিপলস এবং তালিকার মধ্যে কোনও পারফরম্যান্সের পার্থক্য রয়েছে কি?
উত্তর:
dis
মডিউল একটি ফাংশন জন্য বাইট কোড disassembles এবং tuples এবং তালিকা মধ্যে পার্থক্য দেখতে দরকারী।
এই ক্ষেত্রে, আপনি দেখতে পাচ্ছেন যে কোনও উপাদান অ্যাক্সেস করা অভিন্ন কোড উত্পন্ন করে, তবে একটি টিপল বরাদ্দকরণ একটি তালিকা নির্ধারণের চেয়ে অনেক দ্রুত।
>>> def a():
... x=[1,2,3,4,5]
... y=x[2]
...
>>> def b():
... x=(1,2,3,4,5)
... y=x[2]
...
>>> import dis
>>> dis.dis(a)
2 0 LOAD_CONST 1 (1)
3 LOAD_CONST 2 (2)
6 LOAD_CONST 3 (3)
9 LOAD_CONST 4 (4)
12 LOAD_CONST 5 (5)
15 BUILD_LIST 5
18 STORE_FAST 0 (x)
3 21 LOAD_FAST 0 (x)
24 LOAD_CONST 2 (2)
27 BINARY_SUBSCR
28 STORE_FAST 1 (y)
31 LOAD_CONST 0 (None)
34 RETURN_VALUE
>>> dis.dis(b)
2 0 LOAD_CONST 6 ((1, 2, 3, 4, 5))
3 STORE_FAST 0 (x)
3 6 LOAD_FAST 0 (x)
9 LOAD_CONST 2 (2)
12 BINARY_SUBSCR
13 STORE_FAST 1 (y)
16 LOAD_CONST 0 (None)
19 RETURN_VALUE
ListLike
একটি সঙ্গে __getitem__
যে কিছু ভয়ঙ্করভাবে ধীর, তারপর অবতরণ করে x = ListLike((1, 2, 3, 4, 5)); y = x[2]
। বাইটকোড তালিকার উদাহরণের চেয়ে উপরের টিপলের উদাহরণের মতো আরও হবে, তবে আপনি কি সত্যই বিশ্বাস করেন যে পারফর্মেন্সটি একই রকম হবে?
সাধারণভাবে, আপনি টিপলগুলি কিছুটা দ্রুত হওয়ার আশা করতে পারেন। তবে আপনার অবশ্যই অবশ্যই আপনার নির্দিষ্ট কেসটি পরীক্ষা করা উচিত (যদি পার্থক্যটি আপনার প্রোগ্রামের কার্যকারিতার উপর প্রভাব ফেলতে পারে - মনে রাখবেন "অকালীন অপটিমাইজেশন সমস্ত মন্দের মূল")।
পাইথন এটি খুব সহজ করে তোলে: সময়কাল আপনার বন্ধু।
$ python -m timeit "x=(1,2,3,4,5,6,7,8)"
10000000 loops, best of 3: 0.0388 usec per loop
$ python -m timeit "x=[1,2,3,4,5,6,7,8]"
1000000 loops, best of 3: 0.363 usec per loop
এবং...
$ python -m timeit -s "x=(1,2,3,4,5,6,7,8)" "y=x[3]"
10000000 loops, best of 3: 0.0938 usec per loop
$ python -m timeit -s "x=[1,2,3,4,5,6,7,8]" "y=x[3]"
10000000 loops, best of 3: 0.0649 usec per loop
সুতরাং এক্ষেত্রে ইনস্ট্যান্টেশন প্রায়শই দ্রুততর আকারের ক্রম হিসাবে দ্রুতগতির জন্য, তবে আইটেম অ্যাক্সেসটি তালিকার জন্য আসলে কিছুটা দ্রুত! সুতরাং আপনি যদি কয়েকটি টিপল তৈরি করে এবং এগুলিতে বহুবার অ্যাক্সেস করেন তবে পরিবর্তে তালিকাগুলি ব্যবহার করা আরও দ্রুত হতে পারে।
অবশ্যই আপনি যদি কোনও আইটেম পরিবর্তন করতে চান তবে তালিকাটি অবশ্যই দ্রুততর হবে কারণ এর একটি আইটেম পরিবর্তন করার জন্য আপনাকে একটি সম্পূর্ণ নতুন টিউপল তৈরি করতে হবে (যেহেতু দ্বৈতগুলি অবিচ্ছেদ্য)।
python -m timeit "x=tuple(xrange(999999))"
বনাম python -m timeit "x=list(xrange(999999))"
। যেহেতু কেউ আশা করতে পারে, তালিকার তুলনায় একটি টিপল তৈরি করতে কিছুটা বেশি সময় নেয়।
-s "SETUP_CODE"
প্রকৃত সুবিধানুযায়ী কোড সামনে চালানো হয়।
টিপলস প্রায় প্রতিটি বিভাগে তালিকার চেয়ে আরও ভাল পারফর্ম করে:
1) টিপলস ধ্রুবক ভাঁজ করা যেতে পারে ।
2) টিপলগুলি অনুলিপি করার পরিবর্তে পুনরায় ব্যবহার করা যেতে পারে।
3) টিপলগুলি কমপ্যাক্ট এবং অতিরিক্ত বরাদ্দ দেয় না।
4) টিপলস সরাসরি তাদের উপাদান রেফারেন্স।
পাইথনের পাইফোল অপটিমাইজার বা এএসটি-অপ্টিমাইজারের দ্বারা ধ্রুবকগুলির বেশিরভাগগুলি প্রাক্পম্প্ট করা যেতে পারে। অন্যদিকে তালিকাগুলি স্ক্র্যাচ থেকে অন্তর্নির্মিত হন:
>>> from dis import dis
>>> dis(compile("(10, 'abc')", '', 'eval'))
1 0 LOAD_CONST 2 ((10, 'abc'))
3 RETURN_VALUE
>>> dis(compile("[10, 'abc']", '', 'eval'))
1 0 LOAD_CONST 0 (10)
3 LOAD_CONST 1 ('abc')
6 BUILD_LIST 2
9 RETURN_VALUE
দৌড়ে tuple(some_tuple)
তত্ক্ষণাত নিজেই ফিরে আসে। যেহেতু টিপলগুলি পরিবর্তনযোগ্য, তাই তাদের অনুলিপি করতে হবে না:
>>> a = (10, 20, 30)
>>> b = tuple(a)
>>> a is b
True
বিপরীতে, list(some_list)
সমস্ত তথ্য একটি নতুন তালিকায় অনুলিপি করা প্রয়োজন:
>>> a = [10, 20, 30]
>>> b = list(a)
>>> a is b
False
যেহেতু একটি টিউপলের আকার স্থির করা হয়েছে, এটিকে অ্যাপেন্ড () ক্রিয়াকলাপকে দক্ষ করার জন্য অতিরিক্ত তালিকাভুক্ত হওয়া তালিকার তুলনায় এটি আরও কমপ্লেট করে সংরক্ষণ করা যেতে পারে ।
এটি টিপলগুলিকে একটি দুর্দান্ত জায়গার সুবিধা দেয়:
>>> import sys
>>> sys.getsizeof(tuple(iter(range(10))))
128
>>> sys.getsizeof(list(iter(range(10))))
200
এখানে অবজেক্টস / লিস্টোবজেক্ট.সি.- এর মন্তব্য যা লিস্টগুলি কী করছে তা ব্যাখ্যা করে:
/* This over-allocates proportional to the list size, making room
* for additional growth. The over-allocation is mild, but is
* enough to give linear-time amortized behavior over a long
* sequence of appends() in the presence of a poorly-performing
* system realloc().
* The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
* Note: new_allocated won't overflow because the largest possible value
* is PY_SSIZE_T_MAX * (9 / 8) + 6 which always fits in a size_t.
*/
অবজেক্টের রেফারেন্সগুলি সরাসরি একটি টিপল অবজেক্টে অন্তর্ভুক্ত করা হয়। বিপরীতে, তালিকাগুলির পয়েন্টারগুলির একটি বাহ্যিক অ্যারেতে ইন্ডায়ারেশনের অতিরিক্ত স্তর থাকে।
এটি টিপলগুলিকে ইনডেক্সড লুকআপ এবং আনপ্যাকিংয়ের জন্য একটি ছোট গতির সুবিধা দেয়:
$ python3.6 -m timeit -s 'a = (10, 20, 30)' 'a[1]'
10000000 loops, best of 3: 0.0304 usec per loop
$ python3.6 -m timeit -s 'a = [10, 20, 30]' 'a[1]'
10000000 loops, best of 3: 0.0309 usec per loop
$ python3.6 -m timeit -s 'a = (10, 20, 30)' 'x, y, z = a'
10000000 loops, best of 3: 0.0249 usec per loop
$ python3.6 -m timeit -s 'a = [10, 20, 30]' 'x, y, z = a'
10000000 loops, best of 3: 0.0251 usec per loop
টিপলটি (10, 20)
কীভাবে সংরক্ষণ করা হয় তা এখানে :
typedef struct {
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
Py_ssize_t ob_size;
PyObject *ob_item[2]; /* store a pointer to 10 and a pointer to 20 */
} PyTupleObject;
তালিকাটি [10, 20]
কীভাবে সংরক্ষণ করা হয় তা এখানে :
PyObject arr[2]; /* store a pointer to 10 and a pointer to 20 */
typedef struct {
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
Py_ssize_t ob_size;
PyObject **ob_item = arr; /* store a pointer to the two-pointer array */
Py_ssize_t allocated;
} PyListObject;
নোট করুন যে টিপল অবজেক্ট দুটি ডাটা পয়েন্টারকে সরাসরি অন্তর্ভুক্ত করে যখন তালিকার অবজেক্টটিতে দুটি ডাটা পয়েন্টার ধারণ করে একটি বাহ্যিক অ্যারেতে ইন্ডায়ারেশনের অতিরিক্ত স্তর থাকে।
Internally, tuples are stored a little more efficiently than lists, and also tuples can be accessed slightly faster.
ডিএফ. এর উত্তর থেকে আপনি কীভাবে ফলাফল ব্যাখ্যা করতে পারবেন?
tuple(some_tuple)
কেবলমাত্র হশযোগ্য হলেই some_tuple
নিজেকে ফিরিয়ে দেয় some_tuple
its যখন এর সামগ্রীগুলি পুনরাবৃত্তভাবে পরিবর্তনযোগ্য এবং হ্যাশযোগ্য হয়। অন্যথায়, tuple(some_tuple)
একটি নতুন tuple ফেরত। উদাহরণস্বরূপ, যখন some_tuple
পরিবর্তনীয় আইটেম থাকে।
টিপলস, অপরিবর্তনীয়, মেমরির আরও দক্ষ; কর্মক্ষমতা জন্য তালিকাগুলি, ধ্রুবক realloc
গুলি ছাড়াই সংযোজন মঞ্জুর করার জন্য সামগ্রিক মেমরি । সুতরাং, যদি আপনি আপনার কোডে (যেমন for direction in 'up', 'right', 'down', 'left':
) মানগুলির ধ্রুব ক্রমটির মাধ্যমে পুনরাবৃত্তি করতে চান, তবে দ্বিপদীগুলি অগ্রাধিকার দেওয়া হয়, যেহেতু এই জাতীয় টিপলগুলি সংকলনের সময়কালে প্রাক-গণনা করা হয়।
অ্যাক্সেসের গতি একই হওয়া উচিত (এগুলি উভয়ই স্মৃতিতে সংশ্লেষযুক্ত অ্যারে হিসাবে সংরক্ষণ করা হয়)।
তবে, alist.append(item)
আপনি atuple+= (item,)
যখন পরিবর্তনীয় ডেটা নিয়ে কাজ করেন তখন তার চেয়ে অনেক বেশি পছন্দ করা হয় । মনে রাখবেন, টিপলগুলি মাঠের নাম ছাড়াই রেকর্ড হিসাবে গণ্য করার উদ্দেশ্যে।
array
আপনার তালিকায় থাকা সমস্ত আইটেম যদি একই সি টাইপের হয় তবে আপনার স্ট্যান্ডার্ড লাইব্রেরিতে মডিউলটিও বিবেচনা করা উচিত । এটি কম স্মৃতি লাগবে এবং দ্রুত হতে পারে।
এখানে কেবলমাত্র এটির জন্য আরও একটি ছোট্ট মানদণ্ড দেওয়া হল ..
In [11]: %timeit list(range(100))
749 ns ± 2.41 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [12]: %timeit tuple(range(100))
781 ns ± 3.34 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [1]: %timeit list(range(1_000))
13.5 µs ± 466 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [2]: %timeit tuple(range(1_000))
12.4 µs ± 182 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [7]: %timeit list(range(10_000))
182 µs ± 810 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [8]: %timeit tuple(range(10_000))
188 µs ± 2.38 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [3]: %timeit list(range(1_00_000))
2.76 ms ± 30.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [4]: %timeit tuple(range(1_00_000))
2.74 ms ± 31.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [10]: %timeit list(range(10_00_000))
28.1 ms ± 266 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [9]: %timeit tuple(range(10_00_000))
28.5 ms ± 447 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
আসুন এগুলি গড়ুন:
In [3]: l = np.array([749 * 10 ** -9, 13.5 * 10 ** -6, 182 * 10 ** -6, 2.76 * 10 ** -3, 28.1 * 10 ** -3])
In [2]: t = np.array([781 * 10 ** -9, 12.4 * 10 ** -6, 188 * 10 ** -6, 2.74 * 10 ** -3, 28.5 * 10 ** -3])
In [11]: np.average(l)
Out[11]: 0.0062112498000000006
In [12]: np.average(t)
Out[12]: 0.0062882362
In [17]: np.average(t) / np.average(l) * 100
Out[17]: 101.23946713590554
আপনি এটিকে প্রায় অসম্পূর্ণ বলতে পারেন।
তবে নিশ্চিত, তালিকার তুলনায় টিপলস কাজটি করতে সময় 101.239%
বা 1.239%
অতিরিক্ত সময় নিয়েছিল ।
টিপলগুলি অপরিবর্তনীয় বলে তালিকার চেয়ে দ্রুত, কিছুটা দক্ষ এবং সে কারণে হওয়া উচিত।
টিপল পড়ার ক্ষেত্রে খুব দক্ষ হওয়ার মূল কারণ হ'ল এটি পরিবর্তনযোগ্য।
কারণগুলি হল তালিকার তুলনায় টিপলগুলি মেমরি ক্যাশে সংরক্ষণ করা যেতে পারে। প্রোগ্রামটি সর্বদা তালিকার মেমরির অবস্থান থেকে পড়া যায় কারণ এটি পরিবর্তনীয় (যে কোনও সময় পরিবর্তন করতে পারে)।