তালিকাগুলি থ্রেড-নিরাপদ?


155

আমি লক্ষ্য করেছি যে প্রায়শই তালিকাগুলির পরিবর্তে এবং একাধিক থ্রেড সহ সারি ব্যবহার করার পরামর্শ দেওয়া হয় .pop()। তালিকাগুলি থ্রেড-নিরাপদ নয়, বা অন্য কোনও কারণে?


1
পাইথনে থ্রেড-নিরাপদ গ্যারান্টিযুক্ত কি তা সর্বদা বলা শক্ত এবং এটিতে থ্রেড সুরক্ষার বিষয়ে যুক্তি দেওয়া খুব কঠিন। এমনকি অত্যন্ত জনপ্রিয় বিটকয়েন ওয়ালেট ইলেক্ট্রামের সম্মতিযুক্ত বাগগুলি সম্ভবত এটি থেকে উদ্ভূত হয়েছে।
সুডো

উত্তর:


182

তালিকাগুলি এগুলি থ্রেড-নিরাপদ। সিপিথনে জিআইএল তাদের একযোগে প্রবেশের হাত থেকে রক্ষা করে এবং অন্যান্য প্রয়োগগুলি তাদের তালিকা বাস্তবায়নের জন্য সূক্ষ্ম দানযুক্ত লক বা একটি সিঙ্ক্রোনাইজড ডেটাটাইপ ব্যবহার করার যত্ন নেয়। যাইহোক, যখন তালিকা নিজেদের না দুর্নীতিগ্রস্ত একই সময়ে অ্যাক্সেস করতে প্রচেষ্টা দ্বারা যেতে পারেন, তালিকা এর ডেটা সংরক্ষিত নয়। উদাহরণ স্বরূপ:

L[0] += 1

যদি অন্য থ্রেড একই জিনিস করে তবে একটি দ্বারা আসলে এল [0] বাড়ানোর গ্যারান্টি নেই, কারণ +=এটি কোনও পারমাণবিক ক্রিয়াকলাপ নয়। (খুব, পাইথনের খুব কম অপারেশনগুলি আসলে পারমাণবিক, কারণ তাদের বেশিরভাগই পাইথন কোডটি নির্বিচারে কল করতে পারে)) আপনার ক্যুইস ব্যবহার করা উচিত কারণ আপনি যদি কেবল একটি সুরক্ষিত তালিকা ব্যবহার করেন না , তবে রেসের কারণে আপনি ভুল আইটেমটি পেতে বা মুছতে পারেন may শর্ত।


1
Deque এছাড়াও থ্রেড-নিরাপদ? এটি আমার ব্যবহারের জন্য আরও উপযুক্ত বলে মনে হচ্ছে।
লেমিয়েন্ট

20
সমস্ত পাইথন অবজেক্টের একই ধরণের থ্রেড-নিরাপদতা রয়েছে - তারা নিজেরাই দুর্নীতিগ্রস্থ হয় না, তবে তাদের ডেটা হতে পারে। সংগ্রহে.উদ্দেশ্যে কিউ.কিউ আইটেমের পিছনে রয়েছে। যদি আপনি দুটি থ্রেড থেকে জিনিস অ্যাক্সেস করেন তবে আপনার সত্যই ক্যু.কুই আইজু ব্যবহার করা উচিত। সত্যিই।
টমাস ওয়াউটারস

10
লেমিয়েন্ট, ডেকি থ্রেড-সেফ। ফ্লুয়েন্ট পাইথনের দ্বিতীয় অধ্যায় থেকে: "ক্লাস কালেকশনস ডেকিক হ'ল একটি থ্রেড-সেফ ডাবল-এন্ড ক্যু যা দ্রুত উভয় প্রান্ত থেকে সন্নিবেশ এবং অপসারণের জন্য ডিজাইন করা হয়েছে। [...] সংযোজন এবং পোপলফিট অপারেশনগুলি পারমাণবিক, তাই ডেকটি নিরাপদ লক ব্যবহারের প্রয়োজন ছাড়াই মাল্টি-থ্রেড অ্যাপ্লিকেশনগুলিতে একটি লাইফো-কাতার হিসাবে ব্যবহার করুন। "
আল সুইগার্ট

3
এই উত্তরটি সিপথন বা পাইথন সম্পর্কে? পাইথনের নিজেই উত্তর কী?
ব্যবহারকারী541686

@Nils: উহ, প্রথম আপনি যে পৃষ্ঠাটি লিঙ্ক CPython পরিবর্তে পাইথন বলছেন কারণ এটি হয় পাইথন ভাষা বর্ণনা। এবং এই দ্বিতীয় লিঙ্কটি আক্ষরিকভাবে বলেছে যে পাইথন ভাষার একাধিক বাস্তবায়ন রয়েছে, কেবলমাত্র এটিই আরও বেশি জনপ্রিয় হয়ে ওঠে। পাইথন সম্পর্কে প্রশ্নটি দেওয়া হয়েছিল, উত্তরে সিপথনের বিশেষত সিপিথনে যা ঘটেছিল তা-ই নয়, পাইথনের যেকোন উপকরণ বাস্তবায়নের ক্ষেত্রে কী ঘটতে পারে তার গ্যারান্টি দেওয়া উচিত তা বর্ণনা করা উচিত।
user541686

89

টমাস 'চমৎকার উত্তর একটি বিন্দু নির্মল করার জন্য, এটা উল্লেখ করা উচিত যে append() হয় থ্রেড নিরাপদ।

এটি কারণ এই যে কোনও উদ্বেগ নেই যে আমরা যখন এটি লিখতে যাই তখন ডেটা পড়া একই জায়গায় থাকবে। অপারেশন ডেটা পড়তে না, এটি শুধুমাত্র লিস্টে ডেটা লিখেছেন।append()


1
পাইলিস্ট_অ্যাপেন্ড মেমরি থেকে পড়ছে। আপনি কি বোঝাতে চেয়েছেন যে এটি পড়ে এবং লেখাগুলি একই জিআইএল লকটিতে ঘটে? github.com/python/cpython/blob/…
অ্যামুইন্টার

1
@ এমভিন্টার হ্যাঁ, পুরো কলটি একটি জিআইএল লকটিতে PyList_Appendসম্পন্ন হয়েছে। এটি সংযোজন একটি বস্তুর একটি রেফারেন্স দেওয়া হয়। সেই বস্তুর বিষয়বস্তুগুলি মূল্যায়নের পরে এবং কল করার আগে তার পরিবর্তিত হতে পারে PyList_Append। তবে এটি এখনও একই জিনিস হবে এবং নিরাপদে সংযুক্ত হবে (যদি আপনি এটি করেন lst.append(x); ok = lst[-1] is xতবে okঅবশ্যই মিথ্যা হতে পারে)। আপনি যে কোডটি উল্লেখ করেছেন সেটি এতে যুক্ত হওয়া বিষয়বস্তু থেকে পড়া হয় না, এটি এন্টার্কট করা ছাড়া। এটি লিপিতে যুক্ত হওয়া তালিকাটি পড়ে এবং পুনরায় প্রকাশ করতে পারে।
গ্রেগগো

3
dotancohen এর বিন্দু যে L[0] += xএকটি সঞ্চালন করা হবে __getitem__উপর Lএবং তারপর একটি __setitem__উপর Lতাহলে - Lসমর্থন __iadd__এটা বস্তুর ইন্টারফেসে ভিন্নভাবে একটু কাজ করবেন, কিন্তু এখনও দুটি পৃথক অপারেশন হয় Lপাইথন ইন্টারপ্রেটার পর্যায়ে (আপনি তাদের মধ্যে দেখতে হবে সংকলিত বাইটকোড)। appendবাইটকোড মধ্যে Aa একক পদ্ধতি কলে সম্পন্ন করা হয়।
গ্রেগগো

6
কীভাবে remove?
এ্যাক্রাজিং

2
upvoted! সুতরাং আমি কি এক টানা একটানা যুক্ত করতে এবং অন্য থ্রেডে পপ করতে পারি?
পাইরেটএপ

38

এখানে উদাহরণ ব্যাপক এখনো অ সম্পূর্ণ তালিকা এর listঅপারেশন কিনা তারা থ্রেড নিরাপদ। এখানেobj in a_list ভাষা নির্মাণ সম্পর্কিত একটি উত্তর পাওয়ার আশা করছি ।


প্রথম লিঙ্কটি মারা গেছে বলে মনে হচ্ছে।
displayname

2

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

ফ্ল্যাশ সংস্করণ

import threading
import time

# Change this number as you please, bigger numbers will get the error quickly
count = 1000
l = []

def add():
    for i in range(count):
        l.append(i)
        time.sleep(0.0001)

def remove():
    for i in range(count):
        l.remove(i)
        time.sleep(0.0001)


t1 = threading.Thread(target=add)
t2 = threading.Thread(target=remove)
t1.start()
t2.start()
t1.join()
t2.join()

print(l)

আউটপুট যখন ERROR

Exception in thread Thread-63:
Traceback (most recent call last):
  File "/Users/zup/.pyenv/versions/3.6.8/lib/python3.6/threading.py", line 916, in _bootstrap_inner
    self.run()
  File "/Users/zup/.pyenv/versions/3.6.8/lib/python3.6/threading.py", line 864, in run
    self._target(*self._args, **self._kwargs)
  File "<ipython-input-30-ecfbac1c776f>", line 13, in remove
    l.remove(i)
ValueError: list.remove(x): x not in list

লক ব্যবহার করে এমন সংস্করণ

import threading
import time
count = 1000
l = []
lock = threading.RLock()
def add():
    with lock:
        for i in range(count):
            l.append(i)
            time.sleep(0.0001)

def remove():
    with lock:
        for i in range(count):
            l.remove(i)
            time.sleep(0.0001)


t1 = threading.Thread(target=add)
t2 = threading.Thread(target=remove)
t1.start()
t2.start()
t1.join()
t2.join()

print(l)

আউটপুট

[] # Empty list

উপসংহার

পূর্ববর্তী উত্তরে যেমন উল্লিখিত হয়েছে যে তালিকা থেকে উপাদানগুলিকে সংযোজন বা পপ করার কাজটি থ্রেড নিরাপদ, থ্রেডটি নিরাপদ নয় যা আপনি যখন একটি থ্রেডে যুক্ত হন এবং অন্যটিতে পপ করেন


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

1
এছাড়াও, আপনি with r:স্পষ্টভাবে কল করার পরিবর্তে একটি প্রসঙ্গ পরিচালক ( ) ব্যবহার করা ভাল r.acquire()এবংr.release()
গর্ডনএইচজে

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