একটি 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
সুতরাং lists এর চেয়ে কমপক্ষে 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পরিবর্তনীয়। আপনি এটিতে বা এটি থেকে আইটেমগুলি যুক্ত করতে বা সরাতে পারেন। এটি এর আকারটি জানতে হবে (অভ্যন্তরীণ ইমপ্লিমেন্টের জন্য)। এটি প্রয়োজন অনুসারে আকার পরিবর্তন করে।
কোনও নিখরচায় খাবার নেই - এই ক্ষমতাগুলি ব্যয় সহ আসে। অতএব তালিকার জন্য মেমরির ওভারহেড।
টিউলের আকারটি উপসর্গযুক্ত, অর্থাত্ দ্বিপ্রান্তের সূচনাতে দোভাষী অন্তর্ভুক্ত ডেটার জন্য পর্যাপ্ত জায়গা বরাদ্দ করেন এবং এটি শেষ হয়ে যায়, এটিকে অপরিবর্তনীয় (সংশোধন করা যায় না) দেওয়া হয়, তবে একটি তালিকা একটি পরিবর্তনীয় অবজেক্ট তাই গতিশীল বোঝায় মেমরির বরাদ্দ, সুতরাং প্রতিবারের জন্য তালিকা সংযোজন বা সংশোধন করার জন্য স্থান বরাদ্দ এড়াতে (পরিবর্তিত ডেটা ধারণ করার জন্য পর্যাপ্ত জায়গা বরাদ্দ করুন এবং এতে ডেটা অনুলিপি করুন), এটি ভবিষ্যতের সংযোজন, পরিবর্তন, ... জন্য অতিরিক্ত জায়গা বরাদ্দ করে দেয় যা অনেক বেশি এটির পরিমাণ