এএসপি.নিট এমভিসি তে অ্যাসিঙ্ক্রোনাস অপারেশন করুন। নেট 4 এ থ্রেডপুল থেকে একটি থ্রেড ব্যবহার করুন


158

এই প্রশ্নের পরে, এএসপি.নেট এমভিসিতে অ্যাসিঙ্ক অপারেশনগুলি ব্যবহার করার সময় এটি আমাকে আরামদায়ক করে তোলে। সুতরাং, আমি এটিতে দুটি ব্লগ পোস্ট লিখেছি:

এএসপি.নেট এমভিসিতে অ্যাসিক্রোনাস অপারেশন সম্পর্কে আমার মনে অনেক ভুল ধারণা রয়েছে।

আমি সর্বদা এই বাক্যটি শুনি: ক্রিয়াকলাপগুলি অবিচ্ছিন্নভাবে চালিত হলে অ্যাপ্লিকেশন আরও ভাল স্কেল করতে পারে

এবং আমি এই ধরণের বাক্যগুলিও অনেক শুনেছি: আপনার যদি ট্র্যাফিকের পরিমাণ খুব বেশি থাকে তবে আপনি আপনার প্রশ্নগুলি তাত্পর্যপূর্ণভাবে সম্পাদন না করা ভাল be এক অনুরোধের জন্য দুটি অতিরিক্ত থ্রেড গ্রহণ করা অন্যান্য আগত অনুরোধগুলি থেকে দূরে সঞ্চার করে।

আমার মনে হয় এই দুটি বাক্যই বেমানান।

থ্রেডপুলটি কীভাবে এএসপি.নেটে কাজ করে সে সম্পর্কে আমার বেশি তথ্য নেই তবে আমি জানি থ্রেডপুলের থ্রেডগুলির জন্য সীমিত আকার রয়েছে। সুতরাং, দ্বিতীয় বাক্যটি এই সমস্যার সাথে সম্পর্কিত হতে হবে।

এবং আমি জানতে চাই যে এএসপি.নেট এমভিসিতে অ্যাসিক্রোনাস অপারেশনগুলি। নেট 4 এ থ্রেডপুল থেকে কোনও থ্রেড ব্যবহার করে?

উদাহরণস্বরূপ, আমরা যখন অ্যাসিঙ্ক কনট্রোলার প্রয়োগ করি তখন অ্যাপ স্ট্রাকচারটি কীভাবে হয়? যদি আমি বিপুল ট্র্যাফিক পাই, তবে এসিঙ্ককন্ট্রোলার প্রয়োগ করা কি ভাল ধারণা?

এর বাইরে এমন কেউ আছে যে আমার চোখের সামনে এই কালো পর্দাটি সরিয়ে নিয়ে যায় এবং আমাকে এএসপি.নেট এমভিসি 3 (নেট 4) এ অ্যাসক্রোনারি সম্পর্কিত চুক্তিটি ব্যাখ্যা করতে পারে?

সম্পাদনা:

আমি নীচে এই নথিটি প্রায় শতাধিকবার পড়েছি এবং আমি মূল চুক্তিটি বুঝতে পারি তবে এখনও আমার বিভ্রান্তি আছে কারণ সেখানে খুব বেশি বেমানান মন্তব্য রয়েছে।

ASP.NET MVC তে একটি অ্যাসিঙ্ক্রোনাস কন্ট্রোলার ব্যবহার করা

সম্পাদনা:

ধরে নেওয়া যাক আমার নীচের মতো কন্ট্রোলার অ্যাকশন রয়েছে ( AsyncControllerযদিও এর বাস্তবায়ন নয় ):

public ViewResult Index() { 

    Task.Factory.StartNew(() => { 
        //Do an advanced looging here which takes a while
    });

    return View();
}

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

এই ক্ষেত্রে, এটিতে থ্রেডপুল থেকে কোনও থ্রেড ব্যবহার করতে হবে? যদি তাই হয়, এটি সম্পূর্ণ হওয়ার পরে, সেই থ্রেডের কী হবে? GCএটি সম্পূর্ণ হওয়ার পরে কি আসে এবং পরিষ্কার করা যায়?

সম্পাদনা:

@ ডারিনের উত্তরের জন্য, এখানে অ্যাসিঙ্ক কোডের একটি নমুনা যা ডাটাবেসে কথা বলে:

public class FooController : AsyncController {

    //EF 4.2 DbContext instance
    MyContext _context = new MyContext();

    public void IndexAsync() { 

        AsyncManager.OutstandingOperations.Increment(3);

        Task<IEnumerable<Foo>>.Factory.StartNew(() => { 

           return 
                _context.Foos;
        }).ContinueWith(t => {

            AsyncManager.Parameters["foos"] = t.Result;
            AsyncManager.OutstandingOperations.Decrement();
        });

        Task<IEnumerable<Bars>>.Factory.StartNew(() => { 

           return 
                _context.Bars;
        }).ContinueWith(t => {

            AsyncManager.Parameters["bars"] = t.Result;
            AsyncManager.OutstandingOperations.Decrement();
        });

        Task<IEnumerable<FooBar>>.Factory.StartNew(() => { 

           return 
                _context.FooBars;
        }).ContinueWith(t => {

            AsyncManager.Parameters["foobars"] = t.Result;
            AsyncManager.OutstandingOperations.Decrement();
        });
    }

    public ViewResult IndexCompleted(
        IEnumerable<Foo> foos, 
        IEnumerable<Bar> bars,
        IEnumerable<FooBar> foobars) {

        //Do the regular stuff and return

    }
}

উত্তরের বিষয়ে নিশ্চিত নয়, তবে এটির মূল্যহীন অ্যাসিক্রোনাস এবং মাল্টি-থ্রেডিং আলাদা জিনিস are সুতরাং অ্যাসিনক্রোনাস হ্যান্ডলিং সহ একটি নির্দিষ্ট সংখ্যক থ্রেড থাকা সম্ভব হবে। কী ঘটবে যখন কোনও পৃষ্ঠায় বলার জন্য অবরুদ্ধ করতে হবে, I / O, অন্য পৃষ্ঠাতে একই থ্রেডে চালানোর সুযোগ পাবেন। এই দুটি বিবৃতিটি কীভাবে সত্য হতে পারে, অ্যাসিঙ্ক জিনিসগুলি দ্রুত তৈরি করতে পারে তবে অনেকগুলি থ্রেডই সমস্যা।
ক্রিস চিলভার্স

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

6
ভিডিওটি একবার দেখুন জেফ
রিখরারের

আমি মনে করি সমস্যাটি (এবং এইভাবে অসঙ্গতি) দ্বিতীয় বিবৃতিটি অ্যাসিনক্রোনাস ব্যবহার করে যখন এর অর্থ অনেকগুলি থ্রেড থাকে। এটি এ কারণেই হতে পারে কারণ এসপিএনটি এইভাবে অ্যাসিঙ্ক পৃষ্ঠাগুলি কার্যকর করেছে এবং সুনির্দিষ্ট বাস্তবায়ন সমস্যাটিকে বিভ্রান্ত করেছে (যে বৈশিষ্ট্যটির কারণে যে সমস্যার সৃষ্টি হয় এটি অ্যাসিঙ্ক পৃষ্ঠাগুলি হবে) তবে আমি নির্দিষ্ট প্রয়োগ সম্পর্কে নিশ্চিত নই । সুতরাং হয় তাদের অর্থ "অনেকগুলি থ্রেড", বা ভবিষ্যতের সংস্করণগুলি বাস্তবায়নে পরিবর্তিত হতে পারে বলে তাদের অর্থ "এসপ নেট সংস্করণ এক্সের মধ্যে অ্যাসিঙ্ক পৃষ্ঠাগুলি" mean বা তাদের অর্থ কেবল কোনও পৃষ্ঠার মধ্যে অ্যাসিঙ্ক সম্পাদন করতে থ্রেড পুল ব্যবহার করা।
ক্রিস চিলভার্স

@ ক্রিসচিলভার ওহ, মানুষ! এই মন্তব্যের পরে আমি আরও বিভ্রান্ত হয়েছি: s
tugberk

উত্তর:


177

এখানে একটি চমৎকার নিবন্ধটি আমি আপনাকে সুপারিশ করব সুপারিশটি এএসপি.এনইটি (মূলত যা অ্যাসিক্রোনাস নিয়ামকরা প্রতিনিধিত্ব করে) এ অ্যাসিক্রোনাস প্রসেসিং আরও ভালভাবে বুঝতে reading

প্রথমে একটি স্ট্যান্ডার্ড সিঙ্ক্রোনাস অ্যাকশন বিবেচনা করা যাক:

public ActionResult Index()
{
    // some processing
    return View();
}

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

আসুন এখন অ্যাসিক্রোনাস প্যাটার্নের একটি উদাহরণ নেওয়া যাক:

public void IndexAsync()
{
    // perform some processing
}

public ActionResult IndexCompleted(object result)
{
    return View();
}

সূচক ক্রিয়ায় কোনও অনুরোধ প্রেরণ করা হলে, থ্রেড পুল থেকে একটি থ্রেড টানা হয় এবং IndexAsyncপদ্ধতির মূল অংশটি কার্যকর করা হয়। এই পদ্ধতির বডি একবার সম্পাদন শেষ করার পরে থ্রেডটি থ্রেড পুলে ফিরে আসে। তারপরে, স্ট্যান্ডার্ডটি ব্যবহার করে AsyncManager.OutstandingOperations, আপনি একবার অ্যাসিঙ্ক অপারেশন সমাপ্তির ইঙ্গিত IndexCompletedদিলে , থ্রেড পুল থেকে আরেকটি থ্রেড টানা হবে এবং ক্রিয়াটির মূল অংশটি এটিতে কার্যকর করা হয় এবং ফলাফল ক্লায়েন্টকে রেন্ডার করা হয়।

সুতরাং আমরা এই প্যাটার্নটিতে যা দেখতে পাচ্ছি তা হ'ল একটি একক ক্লায়েন্ট এইচটিটিপি অনুরোধ দুটি পৃথক থ্রেড দ্বারা কার্যকর করা যেতে পারে।

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

সুতরাং আমরা যখন জিজ্ঞাসা করতে পারি অ্যাসিক্রোনাস কন্ট্রোলারগুলির আসল সুবিধা আমরা কখন নিতে পারি?

আইএমএইচও আমরা যখন আমাদের / ও নিবিড় কাজগুলি (যেমন দূরবর্তী পরিষেবাগুলিতে ডাটাবেস এবং নেটওয়ার্ক কল) করি তখন আমরা সবচেয়ে বেশি লাভ করতে পারি। আপনার যদি সিপিইউ নিবিড় ক্রিয়াকলাপ থাকে, অ্যাসিঙ্ক্রোনাস ক্রিয়াকলাপগুলি আপনাকে খুব বেশি সুবিধা দেয় না।

তাহলে আমরা কেন I / O নিবিড় কাজগুলি থেকে সুবিধা পেতে পারি? কারণ আমরা I / O সমাপ্তি বন্দরগুলি ব্যবহার করতে পারি । আইওসিপি অত্যন্ত শক্তিশালী কারণ আপনি পুরো ক্রিয়াকলাপটি চালনার সময় সার্ভারে কোনও থ্রেড বা সংস্থান গ্রহণ করেন না।

তারা কিভাবে কাজ করে?

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

ফাইলস্ট্রিম.বেগিনারিড, স্কেলকম্যান্ড.বেগিনএক্সেকিউট, ... এর মতো পদ্ধতির ক্ষেত্রেও একই সত্য ...

একাধিক ডাটাবেস কল সমান্তরাল সম্পর্কে কি? মনে করুন যে আপনার একটি সিঙ্ক্রোনাস কন্ট্রোলার অ্যাকশন রয়েছে যাতে আপনি ক্রমানুসারে 4 টি ব্লকিং ডাটাবেস কল করেছেন। এটি গণনা করা সহজ যে প্রতিটি ডাটাবেস কল যদি 200 মিমি নিয়ে থাকে তবে আপনার নিয়ামক পদক্ষেপটি কার্যকর করতে প্রায় 800 মিমি লাগবে।

আপনার যদি সেই কলগুলি ধারাবাহিকভাবে চালনা করার দরকার না হয় তবে তাদের সমান্তরালভাবে পারফরম্যান্সের উন্নতি করতে হবে?

এটাই বড় প্রশ্ন, যার উত্তর দেওয়া সহজ নয়। হতে পারে আবার নাও হতে পারে. এটি কীভাবে আপনি সেই ডেটাবেস কলগুলি প্রয়োগ করেন তার উপর সম্পূর্ণ নির্ভর করে depend আপনি পূর্বে আলোচিত হিসাবে async নিয়ন্ত্রক এবং I / O সমাপ্তি বন্দরগুলি ব্যবহার করেন আপনি এই নিয়ন্ত্রণকারী ক্রিয়াকলাপ এবং সেইসাথে অন্যান্য ক্রিয়াকলাপকেও বাড়িয়ে তুলবেন, কারণ আপনি শ্রমিক থ্রেডকে একচেটিয়াকরণ করবেন না।

অন্যদিকে আপনি যদি এগুলি খারাপভাবে প্রয়োগ করেন (থ্রেড পুল থেকে কোনও থ্রেডে ব্লক করা ডাটাবেস কল দিয়ে) তবে আপনি মূলত এই ক্রিয়াটি কার্যকর করার সময়টি মোটামুটি 200 মিমি করে কমিয়ে ফেলবেন তবে আপনি 4 কর্মী থ্রেড গ্রাস করেছেন তাই আপনি অন্য অনুরোধগুলির পারফরম্যান্সকে হ্রাস করতে পারে যা সেগুলিতে প্রক্রিয়া করার জন্য পুলের থ্রেডগুলি হারিয়ে যাওয়ার কারণে অনাহারে পরিণত হতে পারে।

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

এখন আপনার উদাহরণ বিবেচনা করুন:

public ViewResult Index() { 

    Task.Factory.StartNew(() => { 
        //Do an advanced looging here which takes a while
    });

    return View();
}

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

এখন নিম্নলিখিতগুলি বিবেচনা করুন:

public ViewResult Index() { 

    new Thread(() => { 
        //Do an advanced looging here which takes a while
    }).Start();

    return View();
}

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


1
সত্যিই বিস্তারিত, ধন্যবাদ! আসুন ধরে নেওয়া যাক, আমাদের System.Threading.Taskভিতরে 4 টি অ্যাসিঙ্ক টাস্ক ( ) চলছে IndexAsync। এই অপারেশনগুলির মধ্যে, আমরা একটি সার্ভারে ডিবি কল করছি making সুতরাং, তাদের সব কি I / O নিবিড় অপারেশন, তাই না? সেক্ষেত্রে আমরা 4 টি আলাদা থ্রেড তৈরি করি (বা থ্রেড-পুল থেকে 4 টি আলাদা থ্রেড পাই)? ধরে নিচ্ছি যে আমার কাছে একটি মাল্টি-কোর মেশিন রয়েছে তারা একই সাথে সমান্তরালে চলতে চলেছে, তাই না?
tugberk

10
@ টগবার্ক, ডাটাবেস কলগুলি আই / ও অপারেশন, তবে এটি কীভাবে আপনি প্রয়োগ করেন তার উপর নির্ভর করবে all আপনি যদি কোনও ব্লকিং ডাটাবেস কল ব্যবহার করেন যেমন SqlCommand.ExecuteReaderআপনি সমস্ত অপচয় করছেন যেহেতু এটি একটি ব্লকিং কল। আপনি যে থ্রেডটিতে এই কলটি চালাচ্ছেন সেটিকে আপনি ব্লক করছেন এবং যদি এই থ্রেডটি পুল থেকে থ্রেড হিসাবে দেখা যায় তবে খুব খারাপ। আপনি শুধুমাত্র উপকৃত হবে যদি আপনি সেই I / O সম্পূর্ণ বন্দর ব্যবহার করুন: SqlCommand.BeginExecuteReader। আপনি যদি যাই করেন না কেন আপনি আইওসিপি ব্যবহার না করে, অ্যাসিঙ্ক কন্ট্রোলার ব্যবহার করবেন না কারণ আপনি আপনার অ্যাপ্লিকেশনটির সামগ্রিক কর্মক্ষমতা থেকে উপকারের চেয়ে আরও বেশি ক্ষতি করতে পারবেন।
দারিন দিমিত্রভ

1
ঠিক আছে, বেশিরভাগ সময় আমি প্রথমে ইএফ কোড ব্যবহার করি। আমি এটি ফিট করে না নিশ্চিত। আমি একটি নমুনা রেখেছি যা দেখায় যে আমি সাধারণত কি করি। আমি প্রশ্নটি আপডেট করেছি, আপনি কি দেখতে পারেন?
tugberk

3
@ টগবার্ক, আপনি এগুলি সমান্তরালভাবে চালাচ্ছেন, সুতরাং আপনি যদি ক্রমানুসারে চালনা করেন তবে মৃত্যুদণ্ডের মোট সময় কম হয়। তবে এগুলি চালানোর জন্য আপনি কর্মী থ্রেড ব্যবহার করেন। আসলে আসলে ইএফ অলস তাই আপনি যখন করবেন _context.Fooআসলে আপনি কোনও কিছুই চালাচ্ছেন না। আপনি কেবল একটি অভিব্যক্তি গাছ তৈরি করছেন। এটি সম্পর্কে অত্যন্ত সতর্কতা অবলম্বন করুন। আপনি যখন ফলাফল ফলাফলের উপরে গণনা শুরু করেন তখনই ক্যোয়ারির সম্পাদনা স্থগিত করা হয়। এবং যদি দৃশ্যে এটি ঘটে তবে এটি পারফরম্যান্সের জন্য বিপর্যয়কর হতে পারে। উত্সাহিতভাবে .ToList()শেষে একটি EF ক্যোয়ারী সংযোজন কার্যকর করতে।
দারিন দিমিত্রভ

2
@ টগবার্ক, আপনার ওয়েব সাইটে সমান্তরালে একাধিক ব্যবহারকারীকে ভারী বোঝার নীচে কীভাবে আচরণ করা হয় তা অনুকরণ করার জন্য আপনার একটি লোড পরীক্ষার সরঞ্জামের প্রয়োজন হবে। মিনি প্রোফাইলার আপনার ওয়েবসাইটে লোড অনুকরণ করতে পারে না। এটি আপনাকে আপনার ADO.NET কোয়েরিগুলি দেখতে ও অনুকূল করতে এবং এমন একক অনুরোধের প্রোফাইল করতে সহায়তা করবে যা যখন আপনার প্রচুর ব্যবহারকারীর দ্বারা আঘাত করা হয় তখন আপনার সাইটটি কীভাবে সত্যিকারের বিশ্বের পরিস্থিতিতে আচরণ করে see
দারিন দিমিত্রভ

49

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

আপনার যদি অ্যাসিঙ্ক কন্ট্রোলার থাকে তবে তারা পুল থেকে একটি থ্রেড পান তবে অনুরোধটি সার্ভিস করার সময় তারা কিছু হওয়ার অপেক্ষায় (এবং সেই থ্রেডটি অন্য কোনও অনুরোধে দেওয়া যেতে পারে) এবং যখন মূল অনুরোধটির কোনও থ্রেডের প্রয়োজন হয় আবার এটি পুল থেকে একটি পায়

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

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

অ্যাসিঙ্ক কন্ট্রোলার ব্যতীত আপনার পিছনের যাত্রীদের আপনাকে আপনার অর্থের সন্ধানের জন্য বয়সের জন্য অপেক্ষা করতে হবে, ইতিমধ্যে বাস ড্রাইভার কোনও কাজ করছে না।

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


8
খুব সুন্দর উপমা। ধন্যবাদ.
পিটসবার্গ ডিবিএ

বর্ণনাটি আমার পছন্দ হয়েছে। ধন্যবাদ
ওমর কানসিজোগলু

এটি ব্যাখ্যা করার দুর্দান্ত উপায় k আপনাকে ধন্যবাদ,
আনন্দ ব্যাস

ডারিনের উত্তরের সংমিশ্রণে আপনার উত্তরটি অ্যাসিঙ্ক নিয়ন্ত্রকদের পিছনে পুরো প্রক্রিয়াটির সমষ্টি করে, এটি কী এবং আরও গুরুত্বপূর্ণভাবে এটি কী নয়!
নির্মান

এটি একটি দুর্দান্ত উপমা, তবে আমার একটাই প্রশ্ন হ'ল আপনার উপমা অনুসারে যে ব্যক্তি তার পকেটে ঝাঁপিয়ে পড়েছিল তা হ'ল আমাদের অ্যাপ্লিকেশনটিতে কোনও প্রকারের কাজ / প্রক্রিয়াকরণ হবে ... সুতরাং আমরা থ্রেডটি ছেড়ে দিলে কী কাজ করবে? চূড়ান্তভাবে এটি অন্য থ্রেড? তাহলে আমরা এখানে কী লাভ করব?
টমুক 17

10

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

public ViewResult Index() { 

    Task.Factory.StartNew(() => { 
        //Do an advanced looging here which takes a while
    });

    return View();
}

দ্বিতীয় বিভাগের অন্তর্গত। ব্যবহারকারী একটি দ্রুত প্রতিক্রিয়া পাবেন তবে সার্ভারে মোট কাজের চাপ বেশি কারণ এটি একই কাজ করতে হবে + থ্রেডিং হ্যান্ডেল করুন।

এর আর একটি উদাহরণ হ'ল:

public ViewResult Index() { 

    Task.Factory.StartNew(() => { 
        //Make async web request to twitter with WebClient.DownloadString()
    });

    Task.Factory.StartNew(() => { 
        //Make async web request to facebook with WebClient.DownloadString()
    });


    //wait for both to be ready and merge the results

    return View();
}

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

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

এমভিসিতে অ্যাসিঙ্ক কন্ট্রোলারগুলির অন্য একটি লক্ষ্য রয়েছে। এখানে বক্তব্যটি হ'ল কিছু না করার আশেপাশে থ্রেডের সিটিং এড়ানো (যা স্কেলাবিলিটিটিকে আঘাত করতে পারে)। এটি কেবলমাত্র যদি এআইপি'র পক্ষ থেকে আপনি কল করছেন তার মধ্যে অ্যাসিঙ্ক পদ্ধতি রয়েছে matters ওয়েবক্লিয়েন্ট.ডাউনলোড স্ট্রিংএসিঙ্ক () পছন্দ করুন।

মুল বক্তব্যটি হ'ল আপনি নতুন অনুরোধগুলি হ্যান্ডেল করতে আপনার থ্রেডটি ফেরত দিতে পারবেন যতক্ষণ না ওয়েব অনুরোধটি শেষ হয় যেখানে এটি আপনাকে কলব্যাক কল করবে যা একই বা নতুন থ্রেড পাবে এবং অনুরোধটি শেষ করবে।

আমি আশা করি আপনি অ্যাসিক্রোনাস এবং সমান্তরাল মধ্যে পার্থক্য বুঝতে পেরেছি। আপনার থ্রেডটি যেখানে বসে আছে তার সমান্তরাল কোডটি মনে করুন এবং ফলাফলটির জন্য অপেক্ষা করুন। অ্যাসিঙ্ক্রোনাস কোড এমন একটি কোড যেখানে কোডটি সম্পন্ন হওয়ার পরে আপনাকে জানানো হবে এবং এর মধ্যে থ্রেড অন্য কাজ করতে পারে।


6

অপারেশনগুলি অবিচ্ছিন্নভাবে চালিত হলে অ্যাপ্লিকেশনগুলি আরও ভাল স্কেল করতে পারে তবে কেবলমাত্র অতিরিক্ত ক্রিয়াকলাপের সেবার জন্য যদি সংস্থান থাকে

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

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

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

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

সম্পাদনা:

আপনার উদাহরণে Task.Factory.StartNewকলটি .NET থ্রেড-পুলে একটি ক্রিয়াকলাপ তৈরি করবে। থ্রেড পুল থ্রেডের প্রকৃতিটি আবার ব্যবহার করতে হবে (প্রচুর থ্রেড তৈরি / ধ্বংসের ব্যয় এড়াতে)। অপারেশন শেষ হয়ে গেলে থ্রেডটি পুনরায় অন্য অনুরোধের মাধ্যমে পুনরায় ব্যবহার করতে পুলে ছেড়ে দেওয়া হবে (আবর্জনা সংগ্রাহক বাস্তবে জড়িত হন না যদি আপনি আপনার অপারেশনগুলিতে কিছু বস্তু তৈরি না করেন, তবে সে ক্ষেত্রে তারা সাধারণ হিসাবে সংগ্রহ করা হয়) scoping)।

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


ধন্যবাদ! আপনার উত্তরটি পড়ার পরে, আমি একটি কোড নমুনা দিয়ে প্রশ্নটি সম্পাদনা করেছি। আপনি একটি চেহারা পেতে পারেন?
tugberk

আমার কাছে আপনার কাছে এখানে একটি যাদু বাক্য রয়েছে: Task.Factory.StartNewকলটি .NET থ্রেড-পুলে একটি ক্রিয়াকলাপ তৈরি করবে। । এই প্রসঙ্গে, এখানে কোনটি সঠিক: 1-) এটি একটি নতুন থ্রেড তৈরি করে এবং এটি শেষ হয়ে গেলে, থ্রেডটি থ্রেডপুলে ফিরে যায় এবং আবার ব্যবহার করার জন্য সেখানে অপেক্ষা করে। ২-) এটি থ্রেডপুল থেকে একটি থ্রেড পায় এবং সেই থ্রেডটি থ্রেডপুলে ফিরে যায় এবং আবার ব্যবহার করার জন্য অপেক্ষা করুন। 3-) এটি সর্বাধিক দক্ষ পদ্ধতির গ্রহণ করে এবং সেগুলির মধ্যে যে কোনও একটি করতে পারে।
tugberk

1
থ্রেড-পুলটি প্রয়োজনীয় হিসাবে থ্রেড তৈরি করে এবং যখন থ্রেডগুলি ব্যবহার করা হচ্ছে না তখন তাদের পুনর্ব্যবহার করে। এটির সঠিক আচরণটি সিএলআর সংস্করণে পৃথক হয়েছে। আপনি এটি সম্পর্কে সুনির্দিষ্ট তথ্য পেতে পারেন এখানে এমএসডিএন.ইমক্রোসফটকম /en-us/library/0ka9477y.aspx
পল টার্নার

এটি এখন আমার মনে আকার তৈরি হতে শুরু করে। তো, সিএলআর থ্রেড-পুলের মালিক, তাই না? উদাহরণস্বরূপ, একটি ডাব্লুপিএফ অ্যাপ্লিকেশনটিতে থ্রেড-পুলের ধারণাও রয়েছে এবং এটি সেখানে পুলের সাথেও কাজ করে।
tugberk

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

2

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

http://msdn.microsoft.com/en-us/library/ee728598.aspx

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

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


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

শেষ বাক্যটির জন্য: একটি কন্ট্রোলার অ্যাকশনের অভ্যন্তরে, আমি একটি ডেটাবেস 5 বার আলাদাভাবে জিজ্ঞাসা করছিলাম (আমাকে করতে হয়েছিল) এবং এটি প্রায় 400 এমএস লাগছিল। তারপরে, আমি AsyncController প্রয়োগ করেছি এবং এগুলিকে সমান্তরালে চালাচ্ছি। প্রতিক্রিয়া সময় নাটকীয়ভাবে প্রায় হ্রাস। 200 এমএস। তবে আমি জানিনা যে এটি কতগুলি থ্রেড তৈরি করে, আমার সাথে শেষ হওয়ার পরে সেই থ্রেডগুলির সাথে কী ঘটে যায়, GCআসে এবং ঠিক হয়ে যায় আমার কাজ শেষ করার পরে যাতে আমার অ্যাপ্লিকেশনটির কোনও স্মৃতি ফাঁস না হয়, ইত্যাদি। এই অংশে কোনও ধারণা।
tugberk

একটি ডিবাগার সংযুক্ত করুন এবং এটি সন্ধান করুন।
এআর

0

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

আমি একটি বিশদ ভিডিও দিয়ে এটি ব্যাখ্যা করেছি ( http://www.youtube.com/watch?v=wvg13n5V0V0/ "এমভিসি অ্যাসিঞ্চ নিয়ন্ত্রক এবং থ্রেড অনাহার") যা এমভিসিতে থ্রেড অনাহার কিভাবে ঘটে এবং এমভিসি ব্যবহার করে কীভাবে এটি হ্রাস করা যায় তা দেখায় with অ্যাসিঞ্চ কন্ট্রোলারগুলি perf আমি পারফোন ব্যবহার করে অনুরোধের সারিগুলিও পরিমাপ করেছি যাতে আপনি দেখতে পান যে এমভিসি অ্যাসিঞ্চের জন্য কীভাবে অনুরোধ সারিগুলি হ্রাস হয় এবং সিঙ্ক ক্রিয়াকলাপগুলির জন্য এটি কীভাবে খারাপ।

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