একটি tuple
পাইথন কম মেমরি স্পেস লাগে:
>>> a = (1,2,3)
>>> a.__sizeof__()
48
যেখানে list
গুলি আরও মেমরির স্থান নেয়:
>>> b = [1,2,3]
>>> b.__sizeof__()
64
পাইথন মেমরি পরিচালনায় অভ্যন্তরীণভাবে কী ঘটে?
একটি tuple
পাইথন কম মেমরি স্পেস লাগে:
>>> a = (1,2,3)
>>> a.__sizeof__()
48
যেখানে list
গুলি আরও মেমরির স্থান নেয়:
>>> b = [1,2,3]
>>> b.__sizeof__()
64
পাইথন মেমরি পরিচালনায় অভ্যন্তরীণভাবে কী ঘটে?
উত্তর:
আমি ধরে নিচ্ছি আপনি সিপিথন ব্যবহার করছেন এবং bits৪ বিট (আমি আমার সিপিথন ২.7৪-বিট-তে একই ফলাফল পেয়েছি)। অন্যান্য পাইথন বাস্তবায়নে বা আপনার 32 বাইট পাইথন থাকলে পার্থক্য থাকতে পারে।
বাস্তবায়ন নির্বিশেষে, list
গুলি ভেরিয়েবল-আকারের এবং tuple
গুলি স্থির আকারের হয়।
সুতরাং tuple
গুলি স্ট্রাক্টের মধ্যে সরাসরি উপাদানগুলি সঞ্চয় করতে পারে, অন্যদিকে তালিকাগুলির জন্য ইন্ডিরিয়ারেশনের একটি স্তর প্রয়োজন (এটি উপাদানগুলির একটি পয়েন্টার সঞ্চয় করে)। ইন্ডিয়ারেশনের এই স্তরটি একটি পয়েন্টার, 64৪ বিট সিস্টেমে যেটি bit৪ বিট, তাই 8 বাইটস।
তবে আর একটি জিনিস যা list
করতে পারে: তারা অতিরিক্ত বরাদ্দ দেয়। অন্যথায় list.append
এটি সর্বদা একটি O(n)
অপারেশন হতে পারে - এটিকে আরও বেশি পরিমাণে বরাদ্দ দেওয়ার (আরও দ্রুত !!!) তৈরি করার জন্য । তবে এখন এটি বরাদ্দ করা আকার এবং ভরাট আকারের ( কেবলমাত্র একটি আকার সংরক্ষণের প্রয়োজন, কারণ বরাদ্দ এবং ভরাট আকার সর্বদা অভিন্ন থাকে) তার নজর রাখতে হবে । তার মানে প্রতিটি তালিকায় আরেকটি "আকার" সংরক্ষণ করতে হবে যা 64৪ বিট সিস্টেমে একটি bit৪ বিট পূর্ণসংখ্যা, আবার ৮ বাইট।O(1)
tuple
সুতরাং list
s এর চেয়ে কমপক্ষে 16 বাইটের বেশি মেমরি দরকার tuple
। আমি কেন "কমপক্ষে" বললাম? অতিরিক্ত বরাদ্দের কারণে। অতিরিক্ত বরাদ্দের অর্থ এটি প্রয়োজনের চেয়ে বেশি জায়গা বরাদ্দ করে। তবে অতিরিক্ত তালিকাভুক্তির পরিমাণ আপনি তালিকাটি "কীভাবে" তৈরি করেন এবং সংযোজন / মোছার ইতিহাসের উপর নির্ভর করে:
>>> l = [1,2,3]
>>> l.__sizeof__()
64
>>> l.append(4) # triggers re-allocation (with over-allocation), because the original list is full
>>> l.__sizeof__()
96
>>> l = []
>>> l.__sizeof__()
40
>>> l.append(1) # re-allocation with over-allocation
>>> l.__sizeof__()
72
>>> l.append(2) # no re-alloc
>>> l.append(3) # no re-alloc
>>> l.__sizeof__()
72
>>> l.append(4) # still has room, so no over-allocation needed (yet)
>>> l.__sizeof__()
72
আমি উপরের ব্যাখ্যাটি সহ কিছু চিত্র তৈরি করার সিদ্ধান্ত নিয়েছি। সম্ভবত এগুলি সহায়ক
আপনার উদাহরণে এটি (স্কিম্যাটিকালি) মেমরিতে কীভাবে সংরক্ষণ করা হয়। আমি লাল (ফ্রি-হ্যান্ড) চক্রের সাথে পার্থক্যগুলি হাইলাইট করেছি:
এটি আসলে মাত্র একটি আনুমানিক কারণ কারণ int
বস্তুগুলি পাইথন অবজেক্ট এবং সিপথন এমনকি ছোট ছোট পূর্ণসংখ্যার পুনরায় ব্যবহার করে, তাই স্মৃতিতে থাকা অবজেক্টগুলির সম্ভবত আরও সঠিক উপস্থাপনা (যদিও পাঠযোগ্য নয়) হ'ল:
উপকারী সংজুক:
tuple
পাইথন ২.7-এর সিপিথন সংগ্রহস্থলের কাঠামোlist
পাইথন ২.7-এর সিপিথন সংগ্রহস্থলের কাঠামোint
পাইথন ২.7-এর সিপিথন সংগ্রহস্থলের কাঠামোনোট করুন যে __sizeof__
সত্যিই "সঠিক" আকারটি ফেরায় না! এটি কেবল সঞ্চিত মানগুলির আকার দেয়। তবে আপনি যখন sys.getsizeof
ফলাফলটি ব্যবহার করেন তখন আলাদা হয়:
>>> import sys
>>> l = [1,2,3]
>>> t = (1, 2, 3)
>>> sys.getsizeof(l)
88
>>> sys.getsizeof(t)
72
24 "অতিরিক্ত" বাইট রয়েছে। এগুলি আসল , এটি আবর্জনা সংগ্রহকারী ওভারহেড যা __sizeof__
পদ্ধতিতে হিসাব করে না । এর কারণ আপনাকে সাধারণত যাদু পদ্ধতিগুলি সরাসরি ব্যবহার করার কথা নয় - এই ক্ষেত্রে কীভাবে কীভাবে পরিচালনা করতে হয় তা জানেন এমন ফাংশনগুলি ব্যবহার করুন: sys.getsizeof
(যা আসলে থেকে ফিরে আসা মূল্যে জিসি ওভারহেড যুক্ত করে__sizeof__
)।
list
মেমরি অ্যালোকেশন stackoverflow.com/questions/40018398/...
list()
বা একটি তালিকা বোঝার ক্ষেত্রে আরও জানতে চান useful
আমি সিপিথন কোডবেসে আরও গভীর ডুব নেব যাতে আকারগুলি কীভাবে গণনা করা হয় তা আমরা দেখতে পারি। আপনার নির্দিষ্ট উদাহরণে , কোনও অতিরিক্ত বরাদ্দ কার্যকর করা হয়নি, সুতরাং আমি এটির উপরে স্পর্শ করব না ।
আমি এখানে যেমন 64৪-বিট মান ব্যবহার করব।
এর জন্য আকারটি list
নিম্নলিখিত ফাংশন থেকে গণনা করা হয় list_sizeof
:
static PyObject *
list_sizeof(PyListObject *self)
{
Py_ssize_t res;
res = _PyObject_SIZE(Py_TYPE(self)) + self->allocated * sizeof(void*);
return PyInt_FromSsize_t(res);
}
এখানে Py_TYPE(self)
একটি ম্যাক্রো যে grabs হয় ob_type
এর self
(ফিরে PyList_Type
) যখন _PyObject_SIZE
অন্য ম্যাক্রো যে দখল tp_basicsize
করে ধরণ থেকে। tp_basicsize
হিসাবে গণনা করা হয় sizeof(PyListObject)
যেখানে PyListObject
উদাহরণস্বরূপ struct হয় হয়।
PyListObject
গঠন তিনটি ক্ষেত্র রয়েছে:
PyObject_VAR_HEAD # 24 bytes
PyObject **ob_item; # 8 bytes
Py_ssize_t allocated; # 8 bytes
এগুলির মন্তব্য রয়েছে (যা আমি ছাঁটাই করেছি) সেগুলি কী তা ব্যাখ্যা করে, সেগুলি পড়ার জন্য উপরের লিঙ্কটি অনুসরণ করুন। PyObject_VAR_HEAD
তিন 8 বাইট ক্ষেত্র (মধ্যে বিস্তৃতি ob_refcount
, ob_type
এবং ob_size
তাই ক) 24
বাইট অবদান।
তাই আপাতত res
:
sizeof(PyListObject) + self->allocated * sizeof(void*)
বা:
40 + self->allocated * sizeof(void*)
যদি তালিকার উদাহরণগুলিতে বরাদ্দকৃত উপাদান থাকে। দ্বিতীয় অংশটি তাদের অবদান গণনা করে। self->allocated
যেমন এর নাম থেকেই বোঝা যায়, বরাদ্দকৃত উপাদানগুলির সংখ্যা রয়েছে।
কোনও উপাদান ছাড়াই তালিকার আকার হ'ল গণনা করা হয়:
>>> [].__sizeof__()
40
উদাহরণস্বরূপ কাঠামোর আকার।
tuple
বস্তু একটি tuple_sizeof
ফাংশন সংজ্ঞায়িত করে না । পরিবর্তে, তারা object_sizeof
তাদের আকার গণনা করতে ব্যবহার করে:
static PyObject *
object_sizeof(PyObject *self, PyObject *args)
{
Py_ssize_t res, isize;
res = 0;
isize = self->ob_type->tp_itemsize;
if (isize > 0)
res = Py_SIZE(self) * isize;
res += self->ob_type->tp_basicsize;
return PyInt_FromSsize_t(res);
}
এটি, যেমন list
ধরে রাখে tp_basicsize
এবং, যদি বস্তুর কোনও শূন্য থাকে না tp_itemsize
(অর্থাত্ এটির পরিবর্তনশীল দৈর্ঘ্যের উদাহরণ রয়েছে), এটি টিপলে আইটেমগুলির সংখ্যা (যা এটি দিয়ে যায় Py_SIZE
) দিয়ে বহুগুণ করে tp_itemsize
।
tp_basicsize
স্ট্রাক্ট রয়েছেsizeof(PyTupleObject)
যেখানে আবার ব্যবহার করে :PyTupleObject
PyObject_VAR_HEAD # 24 bytes
PyObject *ob_item[1]; # 8 bytes
সুতরাং, কোনও উপাদান ছাড়াই (যা Py_SIZE
প্রত্যাবর্তন হয় 0
) খালি টিপলসের আকার সমান sizeof(PyTupleObject)
:
>>> ().__sizeof__()
24
তাই না? ঠিক আছে, এখানে একটি বিজোড়তা যার জন্য আমি কোনও ব্যাখ্যা খুঁজে পাইনি, tp_basicsize
এর tuple
গুলি আসলে নীচে গণনা করা হচ্ছে:
sizeof(PyTupleObject) - sizeof(PyObject *)
অতিরিক্ত 8
বাইটগুলি কেন মুছে ফেলা হচ্ছে tp_basicsize
এটি আমি সন্ধান করতে সক্ষম হইনি been (সম্ভাব্য ব্যাখ্যার জন্য এমসিফার্টের মন্তব্য দেখুন)
তবে, এটি আপনার নির্দিষ্ট উদাহরণের মধ্যে পার্থক্য । list
গুলি অনেকগুলি বরাদ্দ উপাদানগুলির আশেপাশে রাখে যা কখন অতিরিক্ত বরাদ্দ দেওয়া হয় তা নির্ধারণে সহায়তা করে।
এখন, যখন অতিরিক্ত উপাদান যুক্ত করা হয়, তালিকাগুলি O (1) সংযোজনগুলি অর্জনের জন্য সত্যই এই অতিরিক্ত বরাদ্দটি সম্পাদন করে। এমপিফার্টস এর উত্তরে সুন্দরভাবে কভার করায় এর ফলে এটি আরও বৃহত্তর আকারের হতে পারে।
ob_item[1]
বেশিরভাগই স্থানধারক (সুতরাং এটি বুনিয়াদি থেকে বিয়োগ করে বোঝায়)। tuple
ব্যবহার বরাদ্দ করা হয় PyObject_NewVar
। আমি বিশদটি সন্ধান করতে পারিনি যাতে এটি কেবল একটি শিক্ষিত অনুমান ...
এমসিফার্ট উত্তরটি এটিকে বিস্তৃতভাবে আবরণ করে; এটিকে সহজ রাখতে আপনি ভাবতে পারেন:
tuple
অপরিবর্তনীয় এটি সেট হয়ে গেলে আপনি এটি পরিবর্তন করতে পারবেন না। সুতরাং আপনি আগে থেকেই জানেন যে আপনাকে সেই বস্তুর জন্য কত মেমরি বরাদ্দ করতে হবে।
list
পরিবর্তনীয়। আপনি এটিতে বা এটি থেকে আইটেমগুলি যুক্ত করতে বা সরাতে পারেন। এটি এর আকারটি জানতে হবে (অভ্যন্তরীণ ইমপ্লিমেন্টের জন্য)। এটি প্রয়োজন অনুসারে আকার পরিবর্তন করে।
কোনও নিখরচায় খাবার নেই - এই ক্ষমতাগুলি ব্যয় সহ আসে। অতএব তালিকার জন্য মেমরির ওভারহেড।
টিউলের আকারটি উপসর্গযুক্ত, অর্থাত্ দ্বিপ্রান্তের সূচনাতে দোভাষী অন্তর্ভুক্ত ডেটার জন্য পর্যাপ্ত জায়গা বরাদ্দ করেন এবং এটি শেষ হয়ে যায়, এটিকে অপরিবর্তনীয় (সংশোধন করা যায় না) দেওয়া হয়, তবে একটি তালিকা একটি পরিবর্তনীয় অবজেক্ট তাই গতিশীল বোঝায় মেমরির বরাদ্দ, সুতরাং প্রতিবারের জন্য তালিকা সংযোজন বা সংশোধন করার জন্য স্থান বরাদ্দ এড়াতে (পরিবর্তিত ডেটা ধারণ করার জন্য পর্যাপ্ত জায়গা বরাদ্দ করুন এবং এতে ডেটা অনুলিপি করুন), এটি ভবিষ্যতের সংযোজন, পরিবর্তন, ... জন্য অতিরিক্ত জায়গা বরাদ্দ করে দেয় যা অনেক বেশি এটির পরিমাণ