বর্তমান সিঙ্ক্রোনাইজেশন কনটেক্সটটি কোনও টাস্কশেডুলার হিসাবে ব্যবহার করা যাবে না


100

আমি আমার ভিউমোডেলে দীর্ঘ চলমান সার্ভার কল চালানোর জন্য টাস্কগুলি ব্যবহার করছি এবং ফলাফলগুলি মার্শাল করে Dispatcherব্যবহার করা হয়েছে TaskScheduler.FromSyncronizationContext()। উদাহরণ স্বরূপ:

var context = TaskScheduler.FromCurrentSynchronizationContext();
this.Message = "Loading...";
Task task = Task.Factory.StartNew(() => { ... })
            .ContinueWith(x => this.Message = "Completed"
                          , context);

আমি অ্যাপ্লিকেশনটি কার্যকর করিলে এটি কাজ করে। তবে আমি যখন আমার NUnitপরীক্ষা চালিয়ে Resharperযাই তখন কলটিতে আমি ত্রুটি বার্তাটি পাই FromCurrentSynchronizationContext:

বর্তমান সিঙ্ক্রোনাইজেশন কনটেক্সটটি কোনও টাস্কশেডুলার হিসাবে ব্যবহার করা যাবে না।

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


আমার ক্ষেত্রে আমি TaskScheduler.FromCurrentSynchronizationContext()একটি ল্যাম্বডায় ব্যবহার করছিলাম এবং মৃত্যুদন্ড কার্যকর করা অন্য থ্রেডে পিছিয়ে দেওয়া হয়েছিল। লাম্বদার বাইরের প্রসঙ্গে সমস্যাটি সমাধান করা।
এমকাজেম আখগারি

উত্তর:


146

আপনাকে একটি সিঙ্ক্রোনাইজেশন কনটেক্সট সরবরাহ করতে হবে। এইভাবে আমি এটি পরিচালনা করি:

[SetUp]
public void TestSetUp()
{
  SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
}

6
এমএসটিস্টের জন্য: ClassInitializeAttribute দিয়ে চিহ্নিত পদ্ধতিতে উপরে কোডটি রাখুন।
ড্যানিয়েল বিয়ার

6
@ সাকো: আসলে, আমাকে এটিকে একটি পদ্ধতিতে রেখে দিতে হবে TestInitializeAttribute, অন্যথায় কেবল প্রথম পরীক্ষায় উত্তীর্ণ হয়।
থোররিন

4
এক্সুনিট পরীক্ষার জন্য, আমি এটি স্ট্যাটিক টাইপ কর্টারে রাখি, কারণ এটি কেবলমাত্র একবারে সেটআপ করা দরকার।
কোডকাইজন

4
এই উত্তরটি কেন সমাধান হিসাবে গৃহীত হয়েছিল তা আমি মোটেই বুঝতে পারি না। এটা কাজ করে না. এবং কারণটি সহজ: সিঙ্ক্রোনাইজেশন কনটেক্সট হ'ল একটি ডামি ক্লাস যার প্রেরণ / পোস্ট ফাংশন অকেজো। এই শ্রেণিটি একটি কংক্রিট শ্রেণীর চেয়ে বিমূর্ত হওয়া উচিত যা সম্ভবত "এটি কাজ করছে" এর মিথ্যা ধারায় মানুষকে নিয়ে যায়। @ টফুটিম আপনি সম্ভবত সিঙ্ককন্টেক্সট থেকে প্রাপ্ত নিজস্ব বাস্তবায়ন সরবরাহ করতে চান।
h9uest

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

25

রিচ মেল্টনের সমাধানটি আমার পক্ষে কার্যকর হয়নি। এটি কারণ আমার TestInitializeফাংশনটি async, যেমন আমার পরীক্ষাগুলি রয়েছে, তাই প্রতিটির সাথে awaitবর্তমান সজ্জিত SynchronizationContextহয়। এটি কারণ এমএসডিএন হিসাবে উল্লেখ করা হয়েছে, SynchronizationContextবর্গটি "বোবা" এবং কেবল থ্রেড পুলে সমস্ত কাজ করে।

আমার জন্য যা কাজ করেছিল তা আসলে FromCurrentSynchronizationContextকলটি বাদ দিচ্ছে যখন সেখানে নেই SynchronizationContext(এটি যদি বর্তমান প্রসঙ্গটি বাতিল হয় )। যদি কোনও ইউআই থ্রেড না থাকে তবে আমার এটির সাথে প্রথম স্থানে সিঙ্ক্রোনাইজ করার দরকার নেই।

TaskScheduler syncContextScheduler;
if (SynchronizationContext.Current != null)
{
    syncContextScheduler = TaskScheduler.FromCurrentSynchronizationContext();
}
else
{
    // If there is no SyncContext for this thread (e.g. we are in a unit test
    // or console scenario instead of running in an app), then just use the
    // default scheduler because there is no UI thread to sync with.
    syncContextScheduler = TaskScheduler.Current;
}

আমি বিকল্পগুলির চেয়ে এই সমাধানটি আরও সোজা পেয়েছি, যেখানে:

  • TaskSchedulerভিউমোডেলে একটি পাস করুন (নির্ভরতা ইনজেকশনের মাধ্যমে)
  • SynchronizationContextপরীক্ষা চালানোর জন্য একটি পরীক্ষা এবং একটি "জাল" ইউআই থ্রেড তৈরি করুন - এটির জন্য আমার পক্ষে আরও ঝামেলা

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


আপনার elseকেস একটি উইন্ডোজ পরিষেবা অ্যাপ্লিকেশনটিতেও ব্যর্থ হবে, ফলস্বরূপsyncContextScheduler == null
FindOutIslamNow

একই সমস্যা জুড়ে এসেছিল, তবে পরিবর্তে আমি NUnit উত্স কোডটি পড়েছি। অ্যাসিঙ্কটোসাইঙ্ক অ্যাডাপ্টার কেবল আপনার সিঙ্ক্রোনাইজেশন কনটেক্সটকে ওভাররাইড করে যদি এটি কোনও স্টা থ্রেডে চলছে। একটি শ্রেণিবদ্ধ হল একটি [RequiresThread]গুণকে দিয়ে আপনার শ্রেণিকে চিহ্নিত করা।
অ্যারন

1

সিঙ্ক্রোনাইজেশন কনটেক্সট কাজের গ্যারান্টি থাকতে আমি একাধিক সমাধান একত্রিত করেছি:

using System;
using System.Threading;
using System.Threading.Tasks;

public class CustomSynchronizationContext : SynchronizationContext
{
    public override void Post(SendOrPostCallback action, object state)
    {
        SendOrPostCallback actionWrap = (object state2) =>
        {
            SynchronizationContext.SetSynchronizationContext(new CustomSynchronizationContext());
            action.Invoke(state2);
        };
        var callback = new WaitCallback(actionWrap.Invoke);
        ThreadPool.QueueUserWorkItem(callback, state);
    }
    public override SynchronizationContext CreateCopy()
    {
        return new CustomSynchronizationContext();
    }
    public override void Send(SendOrPostCallback d, object state)
    {
        base.Send(d, state);
    }
    public override void OperationStarted()
    {
        base.OperationStarted();
    }
    public override void OperationCompleted()
    {
        base.OperationCompleted();
    }

    public static TaskScheduler GetSynchronizationContext() {
      TaskScheduler taskScheduler = null;

      try
      {
        taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
      } catch {}

      if (taskScheduler == null) {
        try
        {
          taskScheduler = TaskScheduler.Current;
        } catch {}
      }

      if (taskScheduler == null) {
        try
        {
          var context = new CustomSynchronizationContext();
          SynchronizationContext.SetSynchronizationContext(context);
          taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
        } catch {}
      }

      return taskScheduler;
    }
}

ব্যবহার:

var context = CustomSynchronizationContext.GetSynchronizationContext();

if (context != null) 
{
    Task.Factory
      .StartNew(() => { ... })
      .ContinueWith(x => { ... }, context);
}
else 
{
    Task.Factory
      .StartNew(() => { ... })
      .ContinueWith(x => { ... });
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.