পাইথন তালিকার তুলনায় টিপলগুলি কি আরও দক্ষ?


225

উপাদানগুলি ইনস্ট্যান্টেশন এবং পুনরুদ্ধারের ক্ষেত্রে টিপলস এবং তালিকার মধ্যে কোনও পারফরম্যান্সের পার্থক্য রয়েছে কি?



2
: আপনি পরিবর্তনশীল মধ্যে মেমরি ব্যবহার আগ্রহী টাইপ এই চক্রান্ত আমি তৈরি দেখতে stackoverflow.com/a/30008338/2087463
tmthydvnprt

উত্তর:


172

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

66
ত্রুটি, ঠিক একই বাইটোকডটি উত্পন্ন হওয়ার অর্থ সি'র (এবং সেইজন্য সিপিইউ) স্তরে একই ক্রিয়াকলাপ ঘটে না তার অর্থ এই নয়। একটি বর্গ তৈরি করার চেষ্টা করুন ListLikeএকটি সঙ্গে __getitem__যে কিছু ভয়ঙ্করভাবে ধীর, তারপর অবতরণ করে x = ListLike((1, 2, 3, 4, 5)); y = x[2]। বাইটকোড তালিকার উদাহরণের চেয়ে উপরের টিপলের উদাহরণের মতো আরও হবে, তবে আপনি কি সত্যই বিশ্বাস করেন যে পারফর্মেন্সটি একই রকম হবে?
mzz

2
দেখে মনে হচ্ছে আপনি বলছেন যে কিছু ধরণের অন্যদের চেয়ে বেশি দক্ষ। এটি বোধগম্য হয়, তবে তালিকার ও দ্বিগুণ প্রজন্মের ওভারহেড জড়িত ডেটা টাইপকে অরথোগোনাল বলে মনে হয়, এই সতর্কতার সাথে তারা তালিকাগুলি একই ডেটা টাইপের টাইপস।
মার্ক হ্যারিসন

11
বাইট-কোডের সংখ্যা, যেমন লাইন অফ-কোডের সংখ্যার, কার্যকর করার গতির সাথে সামান্য সম্পর্ক রাখে (এবং তাই দক্ষতা এবং কার্য সম্পাদন)।
মার্টিনো

18
অপশন গণনা থেকে আপনি যে কোনও সিদ্ধান্তে পৌঁছাতে পারেন এমন পরামর্শটি বিপথগামী হলেও এটি মূল পার্থক্যটি দেখায়: ধ্রুবক টিউপসগুলি বাইটকোডে সংরক্ষণ করা হয় এবং ব্যবহারের সময় কেবল রেফারেন্স করা হয়, তবে রানটাইমটিতে তালিকা তৈরি করা দরকার need
পুলি

6
এই উত্তরটি আমাদের দেখায় যে পাইথন টুপল ধ্রুবককে স্বীকার করে। এটা জানা ভাল! তবে পরিবর্তনশীল মানগুলি থেকে একটি টিপল বা একটি তালিকা তৈরির চেষ্টা করার পরে কী ঘটে?
টম

211

সাধারণভাবে, আপনি টিপলগুলি কিছুটা দ্রুত হওয়ার আশা করতে পারেন। তবে আপনার অবশ্যই অবশ্যই আপনার নির্দিষ্ট কেসটি পরীক্ষা করা উচিত (যদি পার্থক্যটি আপনার প্রোগ্রামের কার্যকারিতার উপর প্রভাব ফেলতে পারে - মনে রাখবেন "অকালীন অপটিমাইজেশন সমস্ত মন্দের মূল")।

পাইথন এটি খুব সহজ করে তোলে: সময়কাল আপনার বন্ধু।

$ 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

সুতরাং এক্ষেত্রে ইনস্ট্যান্টেশন প্রায়শই দ্রুততর আকারের ক্রম হিসাবে দ্রুতগতির জন্য, তবে আইটেম অ্যাক্সেসটি তালিকার জন্য আসলে কিছুটা দ্রুত! সুতরাং আপনি যদি কয়েকটি টিপল তৈরি করে এবং এগুলিতে বহুবার অ্যাক্সেস করেন তবে পরিবর্তে তালিকাগুলি ব্যবহার করা আরও দ্রুত হতে পারে।

অবশ্যই আপনি যদি কোনও আইটেম পরিবর্তন করতে চান তবে তালিকাটি অবশ্যই দ্রুততর হবে কারণ এর একটি আইটেম পরিবর্তন করার জন্য আপনাকে একটি সম্পূর্ণ নতুন টিউপল তৈরি করতে হবে (যেহেতু দ্বৈতগুলি অবিচ্ছেদ্য)।


3
আপনার পরীক্ষা দিয়ে অজগরটির কী সংস্করণ ছিল!
ম্যাট জেন্ডার

2
আরও একটি আকর্ষণীয় পরীক্ষা রয়েছে - python -m timeit "x=tuple(xrange(999999))"বনাম python -m timeit "x=list(xrange(999999))"। যেহেতু কেউ আশা করতে পারে, তালিকার তুলনায় একটি টিপল তৈরি করতে কিছুটা বেশি সময় নেয়।
হামিশ গ্রুবিজন

3
উদ্ভট বলে মনে হচ্ছে যে তালিকার অ্যাক্সেস তালিকার অ্যাক্সেসের চেয়ে ধীর। যাইহোক, আমার উইন্ডোজ 7 পিসিতে পাইথন ২.7 এ চেষ্টা করে, পার্থক্যটি কেবল 10%, তাই গুরুত্বহীন।
টুলমেকারস্টেভ

51
এফডাব্লুআইডাব্লু, তালিকার অ্যাক্সেসটি পাইথন ২ এ দ্বিগুণ অ্যাক্সেসের চেয়ে দ্রুততর তবে কেবল পাইথন / সিভাল.সি.-এর BINARY_SUBSCR- এ তালিকার জন্য বিশেষ মামলা রয়েছে। পাইথন 3-এ, সেই অপ্টিমাইজেশনটি চলে গেছে এবং তালিকার অ্যাক্সেসের তুলনায় টিপলস অ্যাক্সেস সামান্য দ্রুত হয়ে যায়।
রেমন্ড

3
@ আইওপো, প্রথম পরীক্ষাটি মিলিয়ন বার একটি তালিকা তৈরি করে, তবে দ্বিতীয়টি একবারে একটি তালিকা তৈরি করে এবং এটি মিলিয়ন বার অ্যাক্সেস করে। -s "SETUP_CODE"প্রকৃত সুবিধানুযায়ী কোড সামনে চালানো হয়।
লিউজ

203

সারসংক্ষেপ

টিপলস প্রায় প্রতিটি বিভাগে তালিকার চেয়ে আরও ভাল পারফর্ম করে:

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;

নোট করুন যে টিপল অবজেক্ট দুটি ডাটা পয়েন্টারকে সরাসরি অন্তর্ভুক্ত করে যখন তালিকার অবজেক্টটিতে দুটি ডাটা পয়েন্টার ধারণ করে একটি বাহ্যিক অ্যারেতে ইন্ডায়ারেশনের অতিরিক্ত স্তর থাকে।


19
অবশেষে, কেউ সি স্ট্রাক্ট রাখে!
ওসমান

1
Internally, tuples are stored a little more efficiently than lists, and also tuples can be accessed slightly faster. ডিএফ. এর উত্তর থেকে আপনি কীভাবে ফলাফল ব্যাখ্যা করতে পারবেন?
ডিআরজেড

5
~ 100 উপাদান তালিকার ~ 50k তালিকাগুলির সাথে কাজ করার সময়, এই কাঠামোটিকে দ্বিগুণে সরিয়ে নিয়ে একাধিক অনুসন্ধানের জন্য একাধিক আদেশের আকারের দ্বারা অনুসন্ধানের সময় হ্রাস পেয়েছে। আমি বিশ্বাস করি এটি একবার আপনি টিউপলের দ্বিতীয় স্তরের অপসারণের কারণে টিপলটি ব্যবহার শুরু করার পরে টিউপের বৃহত্তর ক্যাশে লোকাল হওয়ার কারণে হবে।
হোর্টা

tuple(some_tuple)কেবলমাত্র হশযোগ্য হলেই some_tupleনিজেকে ফিরিয়ে দেয় some_tupleits যখন এর সামগ্রীগুলি পুনরাবৃত্তভাবে পরিবর্তনযোগ্য এবং হ্যাশযোগ্য হয়। অন্যথায়, tuple(some_tuple)একটি নতুন tuple ফেরত। উদাহরণস্বরূপ, যখন some_tupleপরিবর্তনীয় আইটেম থাকে।
লুসিয়ানো রামালহো

টিপলগুলি সর্বদা দ্রুত হয় না iআপনি সীমার (1,100) জন্য টিউনস (1, `` t = (): t + = আইল = [] আই রেঞ্জে (1,1000): এ.পেন্ড (i) `` `দ্বিতীয়টি দ্রুত
মেলভিল জেমস

32

টিপলস, অপরিবর্তনীয়, মেমরির আরও দক্ষ; কর্মক্ষমতা জন্য তালিকাগুলি, ধ্রুবক reallocগুলি ছাড়াই সংযোজন মঞ্জুর করার জন্য সামগ্রিক মেমরি । সুতরাং, যদি আপনি আপনার কোডে (যেমন for direction in 'up', 'right', 'down', 'left':) মানগুলির ধ্রুব ক্রমটির মাধ্যমে পুনরাবৃত্তি করতে চান, তবে দ্বিপদীগুলি অগ্রাধিকার দেওয়া হয়, যেহেতু এই জাতীয় টিপলগুলি সংকলনের সময়কালে প্রাক-গণনা করা হয়।

অ্যাক্সেসের গতি একই হওয়া উচিত (এগুলি উভয়ই স্মৃতিতে সংশ্লেষযুক্ত অ্যারে হিসাবে সংরক্ষণ করা হয়)।

তবে, alist.append(item)আপনি atuple+= (item,)যখন পরিবর্তনীয় ডেটা নিয়ে কাজ করেন তখন তার চেয়ে অনেক বেশি পছন্দ করা হয় । মনে রাখবেন, টিপলগুলি মাঠের নাম ছাড়াই রেকর্ড হিসাবে গণ্য করার উদ্দেশ্যে।


1
পাইথনে সংকলনের সময় কী?
বালকি

1
@ বালকি: সেই সময় যখন পাইথন উত্সটি বাইটকোডে সংকলিত হয় (যা বাইটোকোড একটি .py [কো] ফাইল হিসাবে সংরক্ষণ করা হতে পারে)।
tzot

যদি সম্ভব হয় একটি প্রশংসা মহান।
গ্রিজেশ চৌহান

9

arrayআপনার তালিকায় থাকা সমস্ত আইটেম যদি একই সি টাইপের হয় তবে আপনার স্ট্যান্ডার্ড লাইব্রেরিতে মডিউলটিও বিবেচনা করা উচিত । এটি কম স্মৃতি লাগবে এবং দ্রুত হতে পারে।


15
এতে কম স্মৃতি লাগবে, তবে অ্যাক্সেসের সময়টি সম্ভবত দ্রুততার চেয়ে কিছুটা ধীর হবে। কোনও উপাদান অ্যাক্সেসের জন্য প্যাকড মানটি একটি সত্যসংখ্যার বাক্সে আনবক্স করা প্রয়োজন, যা প্রক্রিয়াটি কমিয়ে দেবে।
ব্রায়ান

5

এখানে কেবলমাত্র এটির জন্য আরও একটি ছোট্ট মানদণ্ড দেওয়া হল ..

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%অতিরিক্ত সময় নিয়েছিল ।


4

টিপলগুলি অপরিবর্তনীয় বলে তালিকার চেয়ে দ্রুত, কিছুটা দক্ষ এবং সে কারণে হওয়া উচিত।


4
আপনি কেন বলেন যে অপরিবর্তনীয়তা এবং নিজেই, দক্ষতা বৃদ্ধি করে? বিশেষ করে ইনস্ট্যান্টেশন এবং পুনরুদ্ধারের দক্ষতা?
ব্লেয়ার কনরাড

1
মনে হচ্ছে আমার উপরের মার্কের জবাব পাইথনের অভ্যন্তরে কী ঘটেছিল তা বিচ্ছিন্নভাবে নির্দেশাবলী instructionsেকে রেখেছে। আপনি দেখতে পাচ্ছেন যে ইনস্ট্যান্টেশন কম নির্দেশাবলী নেয়, তবে এই ক্ষেত্রে পুনরুদ্ধার দৃশ্যত অভিন্ন।
ctcherry

অপরিবর্তনীয়
টিউপসগুলির

-6

টিপল পড়ার ক্ষেত্রে খুব দক্ষ হওয়ার মূল কারণ হ'ল এটি পরিবর্তনযোগ্য।

কেন অপরিবর্তনীয় জিনিসগুলি পড়া সহজ?

কারণগুলি হল তালিকার তুলনায় টিপলগুলি মেমরি ক্যাশে সংরক্ষণ করা যেতে পারে। প্রোগ্রামটি সর্বদা তালিকার মেমরির অবস্থান থেকে পড়া যায় কারণ এটি পরিবর্তনীয় (যে কোনও সময় পরিবর্তন করতে পারে)।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.