SORU
23 Temmuz 2011, CUMARTESİ


Neden TaskScheduler.Geçerli varsayılan TaskScheduler?

Görev Paralel Kitaplığı büyük ve çok geçtiğimiz aylarda kullandım. Ancak, bir şey beni gerçekten rahatsız ediyor: TaskScheduler.Current varsayılan Görev Zamanlayıcısı olması, TaskScheduler.Default. Bu kesinlikle ne örnekler belgelerinde ilk bakışta açık değildir.

Current davranışını başka bir görev içinde olmanıza bağlı olarak değişiyor bu yana ince hataların yol açabilir. Kolayca tespit edilebilir.

Zaman uyumsuz yöntemleri bir kütüphane, XxxAsync yöntemleri içinde aynı şekilde orijinal senkronizasyon bağlamı üzerinde tamamlama sinyali, standart zaman uyumsuz desen olaylara dayanan kullanarak yazma olduğumu varsayalım .NET Çerçevesi (örneğin DownloadFileAsync). Çok kolay aşağıdaki kodu bu davranışı uygulamak için, çünkü bu uygulama için Görev Paralel Kitaplığı kullanmaya karar verdim.

public class MyLibrary {
    public event EventHandler SomeOperationCompleted;

    private void OnSomeOperationCompleted() {
        var handler = SomeOperationCompleted;
        if (handler != null)
            handler(this, EventArgs.Empty);
    }

    public void DoSomeOperationAsync() {
                    Task.Factory
                        .StartNew
                         (
                            () => Thread.Sleep(1000) // simulate a long operation
                            , CancellationToken.None
                            , TaskCreationOptions.None
                            , TaskScheduler.Default
                          )
                        .ContinueWith
                           (t => OnSomeOperationCompleted()
                            , TaskScheduler.FromCurrentSynchronizationContext()
                            );
    }
}

Şu ana kadar her şey iyi çalışıyor. Şimdi, WPF veya Win uygulaması düğmesini tıklatın: bu kütüphane için bir arama yapmak

private void Button_OnClick(object sender, EventArgs args) {
    var myLibrary = new MyLibrary();
    myLibrary.SomeOperationCompleted  = (s, e) => DoSomethingElse();
    myLibrary.DoSomeOperationAsync();
}

private void DoSomethingElse() {
    ...
    Task.Factory.StartNew(() => Thread.Sleep(5000)/*simulate a long operation*/);
    ...
}

Burada, kişi kütüphane çağrısı yazma işlemi tamamlandığında Task yeni bir başlangıç için seçti. Sıra dışı bir şey yok. O web üzerinde örnekler her yerde takip eder ve sadece TaskScheduler (ikinci parametre de bunu belirtmek için kolay aşırı yük yok) belirtmeden Task.Factory.StartNew kullanın. DoSomethingElse yöntem gayet iyi çalışıyor. yalnız, ama yakında bu çağrılan göre olay, UI donuyor beri TaskFactory.Current yeniden eşitleme kapsamında Görev Zamanlayıcı kütüphanemi devamı.

Bu bulgu, özellikle eğer ikinci görev çağrısı, bazı karmaşık çağrı yığını içinde gömülü aşağı ise biraz zaman alabilir. Tabii ki, düzeltme, burada her şeyin nasıl çalıştığını öğrendikten sonra çok basit: her zaman herhangi bir işlem için TaskScheduler.Default belirtin iş parçacığı havuzu çalışan olacağını düşünüyorsun. Ancak, belki de ikinci görev için başka bir harici kütüphane tarafından başlatılan, bu davranış ve safça belirli bir zamanlayıcı olmadan StartNew kullanma hakkında bilmeden. Oldukça yaygın olduğu için bu davayı bekliyorum.

Kafamı çeviriyorum sonra takım seçimi varsayılan olarak TaskScheduler.Default yerine TaskScheduler.Current kullanmak için VUK yazma anlayamıyorum:

  • Belli değil Default varsayılan değildir! Ve belgelere cidden eksik.
  • Gerçek Görev Zamanlayıcı Current tarafından kullanılan çağrı yığını bağlıdır! Bu davranışı ile değişmezler korumak için.
  • Hantal görev oluşturma seçenekleri ve iptal işareti ilk olarak, daha az okunabilir uzun kuyruklar yol belirtmeniz gerekir beri StartNew Görev Zamanlayıcısı belirtmek için. Bu uzantı yöntemi yazma ya da Default kullanan TaskFactory oluşturarak kontrol altına alınabilir.
  • Çağrı yığını yakalayan var ek performans maliyeti.
  • Ben gerçekten başka bir üst çalışan görev bağımlı olmak bir görev istediğinde, bunu açık kod okuma kolaylığı yerine yığın büyü de güvenmek belirtmek için tercih ederim.

Bu soru biraz öznel gelebilir biliyorum, ama bu davranış olarak neden olarak iyi objektif bir argüman bulamıyorum. Burada bir şey eksik eminim: o size danışıyorum.

CEVAP
23 Temmuz 2011, CUMARTESİ


Geçerli davranış mantıklı bence. Kendi benim Görev Zamanlayıcı oluşturmak ve diğer görevler başlatır bazı görev başlarsanız, muhtemelen tüm görevleri yarattım zamanlayıcı kullanmak istiyorum.

Bazen UI akıştan bir görev başlangıç varsayılan zamanlayıcı kullanan ve bazen de tuhaf olduğunu kabul ediyorum. Ama ne olursa tasarımı olsaydım bu kadar iyi olacağını ben de bilmiyorum.

Özel sorunları ile ilgili olarak:

  • Belirli bir zamanlayıcı üzerinde yeni bir görevi başlatmak için en kolay yolu new Task(lambda).Start(scheduler) olduğunu düşünüyorum. Bu görevi bir şey dönerse tür bağımsız değişkeni belirtmelisiniz dezavantajı vardır. TaskFactory.Create türü çıkarabiliriz.
  • TaskScheduler.FromCurrentSynchronizationContext() yerine Dispatcher.Invoke() kullanabilirsiniz.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • bmarian22

    bmarian22

    22 Aralık 2007
  • David Tedeyev

    David Tedeye

    20 AĞUSTOS 2011
  • 10 Daughters, 2 Sons

    10 Daughters

    10 Mart 2009