আমি কীভাবে একটি সার্বজনীন নির্মাণ আরও দক্ষ করতে পারি?


16

একটি "সার্বজনীন নির্মাণ" একটি ক্রমবর্ধমান বস্তুর জন্য একটি মোড়কের শ্রেণি যা এটি রৈখিক হতে সক্ষম করে তোলে (সমবর্তী অবজেক্টগুলির জন্য একটি দৃ strong় ধারাবাহিকতা শর্ত)। উদাহরণস্বরূপ, জাভাতে [1] থেকে এখানে একটি অভিযোজিত ওয়েট-মুক্ত নির্মাণ রয়েছে, যা একটি অপেক্ষা-মুক্ত সারির অস্তিত্বকে অনুমান করে WFQযা ইন্টারফেসটিকে সন্তুষ্ট করে (যার জন্য কেবল থ্রেডগুলির মধ্যে এক সময়ের conকমত্য প্রয়োজন) এবং একটি Sequentialইন্টারফেস ধরে :

public interface WFQ<T> // "FIFO" iteration
{
    int enqueue(T t); // returns the sequence number of t
    Iterable<T> iterateUntil(int max); // iterates until sequence max
}
public interface Sequential
{
    // Apply an invocation (method + arguments)
    // and get a response (return value + state)
    Response apply(Invocation i); 
}
public interface Factory<T> { T generate(); } // generate new default object
public interface Universal extends Sequential {}

public class SlowUniversal implements Universal
{
    Factory<? extends Sequential> generator;
    WFQ<Invocation> wfq = new WFQ<Invocation>();
    Universal(Factory<? extends Sequential> g) { generator = g; } 
    public Response apply(Invocation i)
    {
        int max = wfq.enqueue(i);
        Sequential s = generator.generate();
        for(Invocation invoc : wfq.iterateUntil(max))
            s.apply(invoc);
        return s.apply(i);
    }
}

সত্যিই ধীর হওয়ার কারণে এই বাস্তবায়ন খুব সন্তোষজনক নয় (আপনি প্রতিটি অনুরোধের কথা মনে রাখবেন, এবং প্রতিটি প্রয়োগে এটি পুনরায় খেলতে হবে - আমাদের ইতিহাসের আকারে রৈখিক রানটাইম রয়েছে)। কোনো উপায় আছে যে আমরা প্রসারিত পারে WFQএবং Sequentialইন্টারফেস (যুক্তিসঙ্গত উপায়ে) যখন একটি নতুন আবাহন প্রয়োগের কিছু পদক্ষেপ সংরক্ষণ করতে আমাদের সচল করতে হয়?

অপেক্ষা-মুক্ত সম্পত্তি না হারিয়ে আমরা কী আরও বেশি দক্ষ করে তুলতে পারি (ইতিহাসের আকারের লিনিয়ার রানটাইম নয়, সাধারণত মেমরির ব্যবহার খুব কম হয়)?

শোধন

একটি "সার্বজনীন নির্মাণ" এমন একটি শব্দ যা আমি নিশ্চিত হয়েছি [1] দ্বারা তৈরি হয়েছিল যা কোনও থ্রেড-অনিরাপদ তবে থ্রেড-সামঞ্জস্যপূর্ণ অবজেক্ট গ্রহণ করে, যা Sequentialইন্টারফেস দ্বারা সাধারণীকরণ করা হয় । অপেক্ষা-মুক্ত সারির সাহায্যে, প্রথম নির্মাণটি থ্রেড-সেফ, অবজেক্টের লিনিয়ারাইজযোগ্য সংস্করণ সরবরাহ করে যা এটি অপেক্ষা-মুক্ত (এটি নির্ধারণবাদ এবং থামিয়ে দেওয়া applyঅপারেশনগুলি ধরে নেয় )।

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

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

পরিভাষা:

  1. অপেক্ষা-মুক্ত - থ্রেডের সংখ্যা বা সময়সূচীর সিদ্ধান্ত গ্রহণ নির্বিশেষে applythread থ্রেডটির জন্য কার্যকরভাবে সীমাবদ্ধ নির্দেশাবলীর অবসান হবে।
  2. লক-ফ্রি - উপরের মত একই, তবে আনবাউন্ডেড এক্সিকিউশন সময়ের সম্ভাবনা স্বীকার করে, কেবলমাত্র সেই ক্ষেত্রে যে আনবাউন্ডেড সংখ্যা applyঅপারেশনগুলি অন্য থ্রেডে সম্পন্ন হচ্ছে। সাধারণত, আশাবাদী সিঙ্ক্রোনাইজেশন স্কিমগুলি এই বিভাগে আসে।
  3. ব্লকিং - সময়সূচীর করুণায় দক্ষতা।

অনুরোধ অনুসারে একটি কার্যকারী উদাহরণ (এখন এমন পৃষ্ঠায় যা শেষ হবে না)

[1] হারলিহী এবং শভিট, মাল্টিপ্রসেসর প্রোগ্রামিংয়ের আর্ট


প্রশ্ন 1 কেবল তখনই জবাবদিহি করতে পারে যদি আমরা জানি যে "কাজ করে" আপনার কী বোঝায়।
রবার্ট হার্ভে

@ রবার্তাহারভে আমি এটিকে সংশোধন করেছি - মোড়কের জন্য অপেক্ষা-মুক্ত হওয়া এবং কাজকর্মগুলি CopyableSequentialবৈধ হওয়ার জন্য "কাজ" করা দরকার - লিনিয়ারাইজিবিলিটি তখন সত্যটি অনুসরণ করা উচিত Sequential
ভিএফ 1

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

@ জিমি জেমস আমি প্রশ্নের অভ্যন্তরে একটি "বর্ধিত মন্তব্য" দিয়ে ব্যাখ্যা করেছি। পরিষ্কার করার জন্য অন্য কোনও জারগন রয়েছে কিনা দয়া করে আমাকে জানান।
ভিএফ 1

মন্তব্যের প্রথম অনুচ্ছেদে আপনি বলেছেন "থ্রেড-অনিরাপদ তবে থ্রেড-সামঞ্জস্যপূর্ণ অবজেক্ট" এবং "অবজেক্টের লিনিয়ারাইজযোগ্য সংস্করণ"। এটির দ্বারা আপনি কী বোঝাতে চেয়েছেন তা স্পষ্ট নয় কারণ থ্রেড-নিরাপদ এবং লিনিয়ারাইজেবল কেবল কার্যকর কার্যকর নির্দেশাবলীর সাথে প্রাসঙ্গিক তবে আপনি সেগুলি অবজেক্টগুলিকে বর্ণনা করতে ব্যবহার করছেন যা ডেটা। আমি অনুমান করি যে আমন্ত্রণ (যা সংজ্ঞায়িত নয়) কার্যকরভাবে একটি পদ্ধতি পয়েন্টার এবং এটি সেই পদ্ধতি যা থ্রেড-নিরাপদ নয়। থ্রেড-সামঞ্জস্যপূর্ণ মানে আমি জানি না ।
জিমি জেমস

উত্তর:


1

এটি কীভাবে সম্পন্ন হয় তার একটি ব্যাখ্যা এবং উদাহরণ এখানে। এমন কিছু অংশ আছে যা পরিষ্কার নয় me

উত্স সহ গিস্ট

সার্বজনীন

আরম্ভ:

থ্রেড সূচকগুলি একটি পরমাণু বর্ধিত ফ্যাশনে প্রয়োগ করা হয়। এটি একটি AtomicIntegerনাম ব্যবহার করে পরিচালিত হয় nextIndex। এই সূচকগুলিকে একটি ThreadLocalদৃষ্টান্তের মাধ্যমে থ্রেডগুলিতে বরাদ্দ করা হয়েছে যা পরবর্তী সূচকটি থেকে nextIndexতা বাড়িয়ে এবং বৃদ্ধি করে নিজেকে সূচনা করে । প্রতিটি থ্রেডের সূচক প্রথমবার পুনরুদ্ধার করার পরে এটি ঘটে। একজন ThreadLocalগত ক্রম এই থ্রেড নির্মিত ট্র্যাক তৈরি করা হয়। এটি সূচিত হয়েছে ০. ক্রমযুক্ত কারখানার অবজেক্ট রেফারেন্সটি পাস এবং সঞ্চিত হয়। দুটি AtomicReferenceArrayদৃষ্টান্ত আকারের তৈরি হয় n। টেল অবজেক্টটি প্রতিটি রেফারেন্সে বরাদ্দ করা হয়, Sequentialকারখানার সরবরাহ করা প্রাথমিক অবস্থায় শুরু করা হয় । nঅনুমোদিত সর্বোচ্চ থ্রেডের সংখ্যা number এই অ্যারেগুলির প্রতিটি উপাদান সংশ্লিষ্ট থ্রেড সূচকের সাথে 'সম্পর্কিত'।

পদ্ধতি প্রয়োগ করুন:

এটি সেই পদ্ধতিটি যা আকর্ষণীয় কাজ করে। এটি নিম্নলিখিতগুলি করে:

  • এই অনুরোধের জন্য একটি নতুন নোড তৈরি করুন: আমার
  • বর্তমান থ্রেডের সূচকে ঘোষনা অ্যারেতে এই নতুন নোডটি সেট করুন

তারপরে ক্রম লুপ শুরু হয়। বর্তমান আহবানটি ক্রমবর্ধমান হওয়া অবধি এটি চলতে থাকবে:

  1. এই থ্রেড দ্বারা নির্মিত সর্বশেষ নোডের ক্রম ব্যবহার করে ঘোষনা অ্যারেতে একটি নোড সন্ধান করুন। এই সম্পর্কে আরও পরে।
  2. যদি কোনও পদক্ষেপ 2 এ নোড পাওয়া যায় তবে এটি এখনও সিকোয়েন্সড হয় নি, এটি চালিয়ে যান, অন্যথায়, কেবলমাত্র বর্তমান অনুরোধের দিকে মনোনিবেশ করুন। এটি কেবলমাত্র অনুরোধ অনুযায়ী অন্য একটি নোডকে সহায়তা করার চেষ্টা করবে।
  3. পদক্ষেপ 3 এ যে কোনও নোড নির্বাচন করা হয়েছিল, শেষ সিকোয়েন্সড নোডের পরে এটি সিকোয়েন্স করার চেষ্টা চালিয়ে যান (অন্যান্য থ্রেড হস্তক্ষেপ করতে পারে)) সাফল্য নির্বিশেষে, বর্তমান থ্রেডগুলি শীর্ষস্থান অনুসারে ফিরে আসা ক্রমের জন্য রেফারেন্স সেট করুন decideNext()

উপরে বর্ণিত নেস্টেড লুপের মূলটি হ'ল decideNext()পদ্ধতি। এটি বুঝতে, আমাদের নোড শ্রেণীর দিকে তাকাতে হবে।

নোড ক্লাস

এই শ্রেণিটি দ্বিগুণ-সংযুক্ত তালিকায় নোডগুলি নির্দিষ্ট করে। এই শ্রেণিতে প্রচুর পদক্ষেপ নেই। বেশিরভাগ পদ্ধতি হ'ল সহজ পুনরুদ্ধার পদ্ধতি যা মোটামুটি স্ব-ব্যাখ্যামূলক হওয়া উচিত।

লেজ পদ্ধতি

এটি ০. এর ক্রম সহ একটি বিশেষ নোড উদাহরণ প্রদান করে simply এটি একটি স্থান-ধারক হিসাবে কাজ করে যতক্ষণ না কোনও অনুরোধ এটি প্রতিস্থাপন করে।

সম্পত্তি এবং সূচনা

  • seq: অনুক্রমের নম্বর, -1 এ প্রারম্ভিক (অর্থহীন)
  • invocation: আমন্ত্রণের মান apply()। নির্মাণ উপর সেট।
  • next: AtomicReferenceফরোয়ার্ড লিঙ্কের জন্য। একবার নির্ধারিত হয়ে গেলে, এটি কখনও পরিবর্তন করা হবে না
  • previous: AtomicReferenceসিকোয়েন্সিংয়ের উপর নির্ধারিত পিছনের লিঙ্কটির জন্য এবং এর দ্বারা সাফ করা হয়েছেtruncate()

পরবর্তী সিদ্ধান্ত নিন

এই পদ্ধতিটি নোডে কেবলমাত্র একটি তুচ্ছ তর্কযুক্ত is সংক্ষেপে, লিঙ্কযুক্ত তালিকার পরবর্তী নোড হিসাবে প্রার্থী হিসাবে একটি নোড দেওয়া হয়। compareAndSet()যদি এটা রেফারেন্স নাল পদ্ধতি চেক করবে এবং তাই যদি, প্রার্থী রেফারেন্স সেট। যদি রেফারেন্সটি ইতিমধ্যে সেট করা থাকে তবে এটি কিছুই করে না। এই অপারেশনটি পারমাণবিক তাই একই মুহুর্তে দু'জন প্রার্থীর প্রস্তাব দেওয়া হলে কেবল একজনকেই নির্বাচন করা হবে। এটি গ্যারান্টি দেয় যে কেবলমাত্র একটি নোড পরের বার হিসাবে নির্বাচিত হবে। যদি প্রার্থী নোডটি নির্বাচিত হয় তবে এটির ক্রমটি পরবর্তী মানটিতে সেট করা হবে এবং এর আগের লিঙ্কটি এই নোডে সেট করা আছে।

ইউনিভার্সাল ক্লাসে ফিরে আসার পদ্ধতি প্রয়োগ করুন ...

decideNext()আমাদের নোড বা announceঅ্যারের থেকে কোনও নোডের সাথে সর্বশেষ সিকোয়েন্সড নোড (যখন চেক করা হবে) ডেকে নিয়ে যাওয়ার পরে দুটি সম্ভাব্য ঘটনা রয়েছে: ১. নোডটি সফলভাবে সিকোয়েন্সড হয়েছিল ২. কিছু থ্রেড এই থ্রেডটিকে প্রাক-খালি করা হয়েছে।

পরবর্তী পদক্ষেপটি এই অনুরোধের জন্য নোড তৈরি করেছে কিনা তা পরীক্ষা করা। এটি ঘটতে পারে কারণ এই থ্রেডটি সফলভাবে এটি সিকোয়েন্স করেছে বা অন্য কোনও থ্রেড এটিকে announceঅ্যারে থেকে তুলেছে এবং আমাদের জন্য এটি সিকোয়েন্সড করেছে। যদি এটি সিকোয়েন্সড না করা হয় তবে প্রক্রিয়াটি পুনরাবৃত্তি হয়। অন্যথায় কলটি এই থ্রেডের সূচকের জন্য ঘোষনা অ্যারে সাফ করে এবং অনুরোধের ফলাফলের মানটি ফিরিয়ে শেষ করে। ঘোষণার অ্যারেটি গ্যারান্টি হিসাবে পরিষ্কার করা হয়েছে যে নোডের আশেপাশে কোনও রেফারেন্স নেই যা নোডকে আবর্জনা সংগ্রহ করা থেকে বিরত রাখতে পারে এবং সেইজন্য সমস্ত নোডকে সেই বিন্দু থেকে লিঙ্ক তালিকায় রেখে দেবে he

পদ্ধতি মূল্যায়ন

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

নিশ্চিতকরণের পদ্ধতি

ensurePrior()পদ্ধতি যুক্ত তালিকা পূর্ববর্তী নোড চেক করে কাজ করে। যদি এটির রাজ্য সেট না করা থাকে তবে পূর্ববর্তী নোডটি মূল্যায়ন করা হবে। নোড যে এটি পুনরাবৃত্তি। পূর্ববর্তী নোডের পূর্বে নোডটি যদি মূল্যায়ন না করা হয় তবে এটি সেই নোডের জন্য মূল্যায়ন এবং আরও অনেক কিছু বলবে।

পূর্ববর্তী নোডের একটি রাষ্ট্র রয়েছে বলে জানা গেছে, আমরা এই নোডকে মূল্যায়ন করতে পারি। শেষ নোডটি পুনরুদ্ধার করা হয় এবং স্থানীয় ভেরিয়েবলের জন্য বরাদ্দ করা হয়। যদি এই রেফারেন্সটি নাল হয় তবে এর অর্থ হ'ল অন্য কোনও থ্রেড এটিকে প্রাক-খালি করেছে এবং ইতিমধ্যে এই নোডকে মূল্যায়ন করেছে; এটি স্থিতি স্থাপন। অন্যথায়, পূর্ববর্তী নোডের রাজ্যটি Sequentialএই নোডের অনুরোধের সাথে অবজেক্টের প্রয়োগ পদ্ধতিতে পাস করা হয় । প্রত্যাবর্তিত রাজ্যটি নোডে সেট করা হয় এবং truncate()পদ্ধতিটি বলা হয়, নোড থেকে পিছনের লিঙ্কটি সাফ করে কারণ এটির আর প্রয়োজন নেই।

মুভফওয়ারওয়ার্ড পদ্ধতি

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

অ্যারে এবং সহায়তা ঘোষণা করুন

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

মূল ধারণাটি হ'ল প্রতিটি থ্রেড সফলভাবে নোড তৈরি করার সাথে সাথে নির্ধারিত ক্রমগুলি একঘেয়েভাবে বৃদ্ধি পাচ্ছে। যদি কোনও থ্রেড বা থ্রেড ক্রমাগতভাবে অন্য থ্রেডটিকে প্রাক-শূন্য করে চলেছে তবে announceঅ্যারেতে অনিবার্য নোডগুলি সন্ধানের জন্য সূচকটি এগিয়ে যাবে। এমনকি বর্তমানে প্রদত্ত নোডটিকে সিক্যুয়েন্স করার চেষ্টা করা প্রতিটি থ্রেড অন্য ধারাবাহিকভাবে ক্রমাগত প্রাক খালি করা থাকলেও শেষ পর্যন্ত সমস্ত থ্রেড সেই নোডটিকে সিক্যুয়েন্স করার চেষ্টা করবে। উদাহরণস্বরূপ, আমরা তিনটি থ্রেড সহ একটি উদাহরণ তৈরি করব।

শুরুতে, তিনটি থ্রেডের মাথা এবং ঘোষিত উপাদানগুলি tailনোডের দিকে নির্দেশ করা হয় । lastSequenceপ্রতিটি থ্রেড জন্য 0।

এই মুহুর্তে, অনুরোধের মাধ্যমে থ্রেড 1 কার্যকর করা হয়। এটি তার শেষ সিকোয়েন্স (শূন্য) এর জন্য ঘোষিত অ্যারেটি পরীক্ষা করে যা বর্তমানে নড যা এটি সূচিতে নির্ধারিত হয়। এটি নোডকে সিক্যুয়েন্স করে এটি lastSequence1 এ সেট করা হয়।

থ্রেড 2 এখন একটি অনুরোধের সাথে কার্যকর করা হয়, এটি শেষ সিকোয়েন্স (শূন্য) এ ঘোষণার অ্যারেটি পরীক্ষা করে এবং দেখে যে এটির সাহায্যের প্রয়োজন নেই এবং তাই এটি অনুরোধের ক্রমটিভ করার চেষ্টা করে। এটি সফল হয় এবং এখন এটি lastSequence2 এ সেট করা আছে।

থ্রেড 3 এখন কার্যকর করা হয়েছে এবং এটি এটি দেখতেও পেল যে নোডটি announce[0]ইতিমধ্যে সিকোয়েন্সড এবং সিকোয়েন্সগুলি এটি নিজস্ব অনুরোধ। এটি lastSequenceএখন 3 এ সেট করা হয়েছে।

এখন থ্রেড 1 আবার প্রার্থনা করা হয়। এটি সূচী 1 এ ঘোষণার অ্যারেটি পরীক্ষা করে এবং এটি ইতিমধ্যে সিকোয়েন্সড অবস্থায় রয়েছে। একসাথে, থ্রেড 2 টি চালু করা হয়েছে। এটি সূচক 2 এ ঘোষণার অ্যারেটি পরীক্ষা করে এবং এটি ইতিমধ্যে সিকোয়েন্সড রয়েছে। থ্রেড 1 এবং থ্রেড 2 উভয়ই এখন তাদের নিজস্ব নোডকে সিকোয়েন্স করার চেষ্টা করে। থ্রেড 2 জিতে এবং এটি ক্রয়ের অনুরোধ করে। এটি lastSequence৪ এ সেট করা হয়েছে ইতিমধ্যে থ্রেড তিনটি চালু করা হয়েছে। এটি সূচকটি এটি পরীক্ষা করে lastSequence(আধুনিক 3) এবং এটি দেখতে পেয়েছে যে নোডটি announce[0]ক্রমযুক্ত হয়নি। থ্রেড 2 আবার একই সাথে অনুরোধ করা হয়েছিল যে থ্রেড 1 এর দ্বিতীয় চেষ্টাতে রয়েছে। থ্রেড ঘথ্রেড 2announce[1] দ্বারা সবে নির্মিত নোডটিতে একটি অনিবার্য প্রার্থনা সন্ধান করে । এটি থ্রেড 2 এর অনুরোধটিকে সিকোয়েন্স করার চেষ্টা করে এবং সফল হয়। থ্রেড 2 এটির নিজস্ব নোড খুঁজে পেয়েছে এবং এটি ক্রমযুক্ত হয়েছে। এটি 5 এর মধ্যে সেট হয়েছে Th থ্রেড 3 এর পরে অনুরোধ করা হয়েছে এবং খুঁজে পাওয়া যায় যে 1 টি থ্রেড থাকা নোডটি এখনও ক্রমযুক্ত নয় এবং এটি করার চেষ্টা করে। ইতিমধ্যে থ্রেড 2 টিও শুরু করা হয়েছে এবং থ্রেড 3 টি প্রাক-শূন্য করে দেওয়া হয়েছে এটি এটি নোডটিকে সিক্যুয়েন্স করে এটি 6 এ নির্ধারণ করে ।announce[1]lastSequenceannounce[0]lastSequence

দরিদ্র থ্রেড ঘ । যদিও থ্রেড 3 এটি সিক্যুয়েন্স করার চেষ্টা করছে, উভয় থ্রেডটি নিয়মিতভাবে নিয়মিতভাবে ব্যর্থ হয়েছে th কিন্তু এই মুহুর্তে। থ্রেড 2 এখন ইঙ্গিত করছে announce[0](6 মড 3)। তিনটি থ্রেড একই অনুরোধটি ক্রমের চেষ্টা করতে প্রস্তুত। কোন থ্রেড সফল হয় তা বিবেচনা না করে, পরবর্তী নোডটি ক্রমযুক্ত হওয়া থ্রেড 1 এর অপেক্ষা অপেক্ষার অর্থ নোড দ্বারা রেফারেন্স করা হবে announce[0]

এটি অনিবার্য। থ্রেডগুলি প্রাক-খালি করার জন্য, অন্যান্য থ্রেডগুলি অবশ্যই নোডগুলি সিকোয়েন্সিং করা উচিত এবং তারা এটি করার সাথে সাথে তারা ক্রমাগত তাদের lastSequenceসামনের দিকে এগিয়ে যাবে। যদি প্রদত্ত থ্রেডের নোডটি ক্রমাগত ধারাবাহিক না হয়, অবশেষে সমস্ত থ্রেডগুলি ঘোষনা অ্যারেতে সূচকটির দিকে নির্দেশ করবে। যে নোডটি সাহায্যের চেষ্টা করছে সেটিকে ক্রমবর্ধমান না করা পর্যন্ত কোনও থ্রেড আর কিছু করবে না, সবচেয়ে খারাপ পরিস্থিতিটি হ'ল সমস্ত থ্রেড একই অনিচ্ছাকৃত নোডের দিকে নির্দেশ করছে। অতএব, যে কোনও অনুরোধের অনুক্রমের জন্য প্রয়োজনীয় সময়টি থ্রেডের সংখ্যার ফাংশন এবং ইনপুটটির আকার নয়।


আপনি কি কোডের কিছু অংশ পেস্টবিনে রেখে দিতে চান? অনেক কিছুই (লকফ্রি লিঙ্কড লিস্টের মতো) কেবল কি এ জাতীয়ভাবে বর্ণনা করা যায়? যখন এতগুলি বিবরণ থাকে তখন সামগ্রিকভাবে আপনার উত্তরটি বোঝা কিছুটা কঠিন। যাই হোক না কেন, এটি আশাব্যঞ্জক মনে হচ্ছে, আমি অবশ্যই এটি সরবরাহ করে কিনা তার গর্ত খনন করতে চাই।
ভিএফ 1

এটি অবশ্যই একটি বৈধ লক-মুক্ত বাস্তবায়নের মতো বলে মনে হচ্ছে তবে এটি যে উদ্বেগের সাথে আমি উদ্বিগ্ন তা এটি হারিয়েছে। লিনিয়ারাইজিবিলিটির প্রয়োজনীয়তা উপস্থিত হওয়ার জন্য একটি "বৈধ ইতিহাস" প্রয়োজন, যা লিঙ্কযুক্ত তালিকার প্রয়োগের ক্ষেত্রে, বৈধ হওয়ার জন্য একটি previousএবং nextপয়েন্টার প্রয়োজন । একটি অপেক্ষা-মুক্ত পদ্ধতিতে একটি বৈধ ইতিহাস বজায় রাখা এবং তৈরি করা কঠিন বলে মনে হচ্ছে।
ভিএফ 1

@ ভিএফ 1 আমি নিশ্চিত যে কোন বিষয়টির দিকে নজর দেওয়া হচ্ছে না। আপনি বাকী মন্তব্যে যা কিছু উল্লেখ করেছেন তা আমার দেওয়া উদাহরণে সম্বোধন করা হয়েছে, যা আমি বলতে পারি তা থেকে।
জিমি জেমস

আপনি অপেক্ষা-মুক্ত সম্পত্তি ছেড়ে দিয়েছেন ।
ভিএফ 1

@ ভিএফ 1 আপনি কীভাবে চিত্রিত করবেন?
জিমি জেমস

0

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

দ্রষ্টব্য : আমি ইউনিভার্সাল ইন্টারফেসটি সরিয়ে এটিকে একটি শ্রেণিতে পরিণত করেছি। ইউনিভার্সাল সিকেন্টিয়াল নিয়ে গঠিত হওয়ার সাথে সাথে এক হওয়াও অযৌক্তিক জটিলতার মতো বলে মনে হচ্ছে তবে আমি কিছু মিস করছি। গড় শ্রেণিতে আমি রাষ্ট্রের পরিবর্তনশীল হিসাবে চিহ্নিত করেছি volatile। কোডটি কাজ করার জন্য এটি প্রয়োজনীয় নয়। রক্ষণশীল হতে (থ্রেডিং সহ একটি ভাল ধারণা) এবং প্রতিটি থ্রেড সমস্ত গণনা (এক সময়) করতে বাধা দেয়।

সিক্যুয়াল ও কারখানা

public interface Sequential<E, S, R>
{ 
  R apply(S priorState);

  S state();

  default boolean isApplied()
  {
    return state() != null;
  }
}

public interface Factory<E, S, R>
{
   S initial();

   Sequential<E, S, R> generate(E input);
}

সার্বজনীন

import java.util.concurrent.ConcurrentLinkedQueue;

public class Universal<I, S, R> 
{
  private final Factory<I, S, R> generator;
  private final ConcurrentLinkedQueue<Sequential<I, S, R>> wfq = new ConcurrentLinkedQueue<>();
  private final ThreadLocal<Sequential<I, S, R>> last = new ThreadLocal<>();

  public Universal(Factory<I, S, R> g)
  { 
    generator = g;
  }

  public R apply(I invocation)
  {
    Sequential<I, S, R> newSequential = generator.generate(invocation);
    wfq.add(newSequential);

    Sequential<I, S, R> last = null;
    S prior = generator.initial(); 

    for (Sequential<I, S, R> i : wfq) {
      if (!i.isApplied() || newSequential == i) {
        R r = i.apply(prior);

        if (i == newSequential) {
          wfq.remove(last.get());
          last.set(newSequential);

          return r;
        }
      }

      prior = i.state();
    }

    throw new IllegalStateException("Houston, we have a problem");
  }
}

গড়

public class Average implements Sequential<Integer, Average.State, Double>
{
  private final Integer invocation;
  private volatile State state;

  private Average(Integer invocation)
  {
    this.invocation = invocation;
  }

  @Override
  public Double apply(State prior)
  {
    System.out.println(Thread.currentThread() + " " + invocation + " prior " + prior);

    state = prior.add(invocation);

    return ((double) state.sum)/ state.count;
  }

  @Override
  public State state()
  {
    return state;
  }

  public static class AverageFactory implements Factory<Integer, State, Double> 
  {
    @Override
    public State initial()
    {
      return new State(0, 0);
    }

    @Override
    public Average generate(Integer i)
    {
      return new Average(i);
    }
  }

  public static class State
  {
    private final int sum;
    private final int count;

    private State(int sum, int count)
    {
      this.sum = sum;
      this.count = count;
    }

    State add(int value)
    {
      return new State(sum + value, count + 1);
    }

    @Override
    public String toString()
    {
      return sum + " / " + count;
    }
  }
}

ডেমো কোড

private static final int THREADS = 10;
private static final int SIZE = 50;

public static void main(String... args)
{
  Average.AverageFactory factory = new Average.AverageFactory();

  Universal<Integer, Average.State, Double> universal = new Universal<>(factory);

  for (int i = 0; i < THREADS; i++)
  {
    new Thread(new Test(i * SIZE, universal)).start();
  }
}

static class Test implements Runnable
{
  final int start;
  final Universal<Integer, Average.State, Double> universal;

  Test(int start, Universal<Integer, Average.State, Double> universal)
  {
    this.start = start;
    this.universal = universal;
  }

  @Override
  public void run()
  {
    for (int i = start; i < start + SIZE; i++)
    {
      System.out.println(Thread.currentThread() + " " + i);

      System.out.println(System.nanoTime() + " " + Thread.currentThread() + " " + i + " result " + universal.apply(i));
    }
  }
}

কোডটি এখানে পোস্ট করার সাথে সাথে আমি কিছু সম্পাদনা করেছি। এটি ঠিক আছে তবে আপনার যদি এটি নিয়ে সমস্যা থাকে তবে আমাকে জানান।


আপনার নিজের উত্তরটি আমার কাছে রাখার দরকার নেই (এর আগে যে কোনও প্রাসঙ্গিক সিদ্ধান্ত থেকে বেরিয়ে আসার জন্য আমি আমার প্রশ্নটি আপডেট করেছি)। দুর্ভাগ্যক্রমে, এই উত্তরটিও প্রশ্নের উত্তর দেয় না, যেহেতু এটি আসলে কোনও স্মৃতিই মুক্ত করে না wfq, তাই আপনাকে এখনও পুরো ইতিহাসটি অতিক্রম করতে হবে - একটি ধ্রুবক ফ্যাক্টর বাদে রানটাইম উন্নত হয়নি improved
ভিএফ

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

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

@ ভিএফ 1 সাম্প্রতিক লিঙ্কযুক্ত কিউয়ের কোডটির দিকে তাকিয়ে, অফার পদ্ধতির অনেকটা লুপ রয়েছে যা আপনি দাবি করেছেন যে অন্য উত্তরটি অপেক্ষা-মুক্তহীন করেছে। "অন্য থ্রেডে হারিয়ে যাওয়া সিএএস প্রতিযোগিতার মন্তব্যটি দেখুন; পরবর্তী পুনরায় পড়ুন"
জিমি জেমস

"প্রাথমিক অবস্থাগুলি মুছে ফেলা সম্ভব হবে" - হুবহু। এটি হওয়া উচিত , তবে অপেক্ষার স্বাধীনতা হারাতে কোডের সূক্ষ্মভাবে পরিচয় করানো সহজ। একটি থ্রেড-ট্র্যাকিং স্কিম কাজ করতে পারে। অবশেষে, আমার কাছে সিএলকিউ উত্সের অ্যাক্সেস নেই, আপনি কি লিঙ্ক করতে চান?
ভিএফ 1
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.