SORU
3 EYLÜL 2012, PAZARTESİ


Görev.Fabrika.() StartNew çağıran iş parçacığı dışında başka bir iş parçacığı kullanmak için garantili?

Bir işlevin yeni bir göreve başlıyorum ama aynı iş parçacığı üzerinde çalıştırmak istemem. Farklı bir tane olduğu sürece bilgiler this question verilen yardımcı olmuyor bu yüzden () çalıştığı umurumda değil.

Aşağıdaki kodu her zaman Task t tekrar girmek için izin vermeden önce TestLock çıkış garantisi mıyım? Yeniden entrency önlemek için önerilen tasarım deseni nedir?

object TestLock = new object();

public void Test(bool stop = false) {
    Task t;
    lock (this.TestLock) {
        if (stop) return;
        t = Task.Factory.StartNew(() => { this.Test(stop: true); });
    }
    t.Wait();
}

Düzenleme:Skeet ve Stephen Jon Toub tarafından aşağıda cevap dayalı, kararlı yeniden kullanılabilirlik önlemek için basit bir şekilde bu uzantı yöntemi olarak gösterildiği bir CancellationToken geçmek olacaktır:

public static Task StartNewOnDifferentThread(this TaskFactory taskFactory, Action action) 
 {
    return taskFactory.StartNew(action: action, cancellationToken: new CancellationToken());
}

CEVAP
3 EYLÜL 2012, PAZARTESİ


Stephen Toub - PFX Team - Bu soru bir üyesi gönderdim. Bana gerçekten hızlı bir şekilde, bir çok detay ile geldi - ve onun metni buraya kopyala yapıştır yapacağım. Ben değil alıntı, kitap okumanın büyük bir miktar teklif edilen metin biter kalkarken daha rahat vanilya, siyah-beyaz, ama gerçekten, bu Stephen bilmiyorum bu kadar şey :) yaptım bu cevap topluluk wiki yansıtan tüm iyilik aşağıda değil gerçekten benim içerik.

Eğer dediğiniz Wait() Görevi tamamladığını, olmayacak, herhangi bir engelleme (sadece bir istisna atar görevi tamamladı bir devlet başka RanToCompletion veya başka dönmek gibi bir nop). Eğer arama Wait() Bir Görevi o zaten yürütülmekte, gerek blok olarak başka bir şey yok olabilir makul yapmak (zaman derim blok, ben de dahil olmak üzere her ikisi de doğru çekirdek tabanlı bekleme ve iplik gibi olur genelde yaptığım bir karışım. Eğer Created bir Görev üzerinde Wait() WaitingForActivation devlet benzer şekilde, görev tamamlanıncaya kadar bloke edecek. Bunların hiçbiri ilginç davası görüşülüyor.

İlginç bir durum olduğunda size çağrı Wait() Görev WaitingToRun devlet, yani bu daha önce atılmış bir TaskScheduler ama bu TaskScheduler olmadı etrafta dolanmaya başladı aslında çalışan Görev temsilcisinin henüz. Bu durumda, Bekle çağrısı Tamam Görev ve zamanlayıcı için bir çağrı yoluyla geçerli iş parçacığı üzerinde çalıştırmak için olsun zamanlayıcı 16* *yöntemi sorar. Zamanlayıcı seçmek için ya da görevi Çalıştır sonra ve üzerinden bir çağrı base.TryExecuteTask ya iade yanlış olduğunu belirtmek için değil, yürütülen görev (genellikle bu yapılır nasıl bir mantık return SomeSchedulerSpecificCondition() ? false : TryExecuteTask(task);.. nedeni TryExecuteTask döndürür bir Boolean bu işler senkronizasyonu sağlamak için verilen bir Görev. sadece hiç bir kez idam). Bu yüzden, eğer bir zamanlayıcı istiyor tamamen yasaklamak satır içi uygulaması Görevi sırasında Bekle, sadece uygulanan return false; Eğer bir zamanlayıcı istiyor için her zaman izin ver satır içi uygulaması mümkün olduğunda, sadece uygulanan return TryExecuteTask(task); mevcut uygulama (her ikisi de .NET 4 ve .NET 4.5 ve istemiyorum şahsen bekliyoruz bu geçiş), varsayılan zamanlayıcı hedefleri Havuzu sağlar satır içi uygulaması için geçerli iş parçacığı Havuzu iş parçacığı ve eğer bu iş parçacığı kişi için önceden sıraya görevi.

Not orada olmayan keyfi yeniden kullanılabilirlik burada, bu varsayılan zamanlayıcı olmayacak pompa keyfi ipliklerini bekleyen bir görev... tek izin bu görev için inlined, ve tabii ki herhangi bir satır içi uygulaması bu görev sırayla yapmaya karar verir. Ayrıca unutmayın Bekle hatta bazı durumlarda zamanlayıcı, yerine blok için tercih sormayacak. Örneğin, geçişte bir CancellationToken iptal edilebilir, veya eğer pas olmayan bir sonsuz zaman aşımı olmaz denemek içi çünkü belki bir keyfi uzun bir süre için satır içi görev yürütme, ya hep ya hiç, ve ben de sonuna kadar önemli ölçüde geciktirmek iptal isteği ya da zaman aşımı. Genel olarak, VUK burada Bekle para yapıyor ve çok fazla iş parçacığı yeniden bu konu israf arasında iyi bir denge kurmaya çalışır. Bu tür bir satır içi uygulaması gerçekten önemli özyinelemeli böl ve yut sorunları, örneğin QuickSort, nerede spawn çoklu görevler ve bekleyin hepsini tam... eğer bu olsaydı yapmadan satır içi uygulaması, çok hızlı bir şekilde kilitlenme gibi egzoz tüm konuları havuzu ve ileride olanlar istediğini vermek.

Beklemek ayrı, bu iş o kadar da (uzaktan) olabilir.Fabrika.StartNew arayın ve orada görevini yerine getiren bitebileceğini, ıff zamanlayıcı kullanılan eşzamanlı olarak QueueTask çağrısı bir parçası olarak görev çalıştırmak için seçti. Zamanlayıcıları yerleşik hiçbiri .NET bunu ben şahsen zamanlayıcı için kötü bir tasarım olacağını düşünüyorum, ama teorik olarak mümkün, örneğin protected override void QueueTask(Task task, bool wasPreviouslyQueued) { return TryExecuteTask(task); }. Bir TaskScheduler kabul etmez Task.Factory.StartNew aşırı Task.Factory durumunda TaskScheduler hedefleri olan TaskFactory, zamanlayıcı kullanır.Mevcut. Bu Task.Factory.StartNew bir Görev bu efsanevi RunSynchronouslyTaskScheduler sıraya içinde arama yaparsanız, ayrıca RunSynchronouslyTaskScheduler için, StartNew arama Görevi eşzamanlı uygulanmasında elde edilen sıra yani. Eğer bu bir kütüphane uygulayan sensin ve çağrılacak nereye gittiğini bilmiyorsun gibi) hakkında endişeleriniz varsa, açıkça TaskScheduler iletebilirsiniz.StartNew çağrı için varsayılan Görev kullanın.Her zaman TaskScheduler.gider (çalıştırmak Varsayılan) veya bir TaskFactory TaskScheduler hedef için yaratılmış.Varsayılan.


EDİT: Tamam, tamamen yanılmışım, ve şu anda görev bekleyen bir konu gibi görünüyorolabilirkaçırıldı. İşte bunun daha basit bir örnek:

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

namespace ConsoleApplication1 {
    class Program {
        static void Main() {
            for (int i = 0; i < 10; i  )
            {
                Task.Factory.StartNew(Launch).Wait();
            }
        }

        static void Launch()
        {
            Console.WriteLine("Launch thread: {0}", 
                              Thread.CurrentThread.ManagedThreadId);
            Task.Factory.StartNew(Nested).Wait();
        }

        static void Nested()
        {
            Console.WriteLine("Nested thread: {0}", 
                              Thread.CurrentThread.ManagedThreadId);
        }
    }
}

Örnek çıktı:

Launch thread: 3
Nested thread: 3
Launch thread: 3
Nested thread: 3
Launch thread: 3
Nested thread: 3
Launch thread: 3
Nested thread: 3
Launch thread: 4
Nested thread: 4
Launch thread: 4
Nested thread: 4
Launch thread: 4
Nested thread: 4
Launch thread: 4
Nested thread: 4
Launch thread: 4
Nested thread: 4
Launch thread: 4
Nested thread: 4

Gördüğünüz gibi, bekleyen iş parçacığı yeni görevi yürütmek için yeniden birçok kez vardır. Eğer bu iş parçacığı bir kilidi alıp almadığını bile olabilir. Kötü re-entrancy. Uygun şok ve endişe duyuyorum :(

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

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • ravinderosahn

    ravinderosah

    20 Temmuz 2009
  • The Amazing Atheist

    The Amazing

    20 Kasım 2006
  • UCBerkeley

    UCBerkeley

    3 Mayıs 2006