2011-10-10 20 views
6

Çalışmanın çoğunun arka plan iş parçacıkları tarafından yapıldığı bir uygulama yazıyorum (10 - 500 iş parçacığı).Uygulamaya nasıl duraklatma/devam ettirme işlevi eklenir?

Duraklatma/sürdürme işlevselliği eklemek istiyorum.

Bunu daha önce Thread.Suspend ve Thread.Resume ile yapabilirsiniz. Ancak bu işlevler artık eskimiş kabul edilir.

Aynı şeyi eşit bir şekilde yapmama izin verecek bir şey var mı?

C#

+0

Yararlı bir yanıt gibi bir şey istiyorsanız, biraz daha fazla bilgi vermeniz gerekir. Bu konuları ne yapıyor? Nasıl başlıyorlar? Hangi koşullar altında "duraklatıldı"? Daha fazla bilgi olmadan, bu soruyu cevaplamak imkansız. –

+2

Bir işlemdeki 500 iş parçacığı, özellikle bir demet zamanın çoğunda uyuyorsa, çok fazla sayıda * iş parçacığı sayısıdır. Tavsiyem, mimarinizi makinede işlemciler olduğundan daha fazla iş parçacığı kullanacak şekilde yeniden tasarlamaktır. İplikler C# içinde çok "ağır"; İşi yapmak için gerekli olan mutlak minimum değeri oluşturmalısınız. Ne yapıyorsun o kadar çok iş parçacığı yaratıyorsun? –

+0

Bu bir web tarama uygulamasıdır. Her iş parçacığı, çoğu web sunucusundan yanıt beklerken zamanının çoğunu geçirir, tüm iş parçacıkları aynı yerde başlatılır ve kullanıcı "duraklat" düğmesine bastığında duraklatılmalıdır. Uygulama genellikle 700m-2G bellek alır ve bunu yapmak için daha iyi bir yol olmadığı sürece bununla tamamım; 500 iş parçacığında bile, uygulama genellikle –

cevap

2

C# yüksek performanslı crawler yazılı olması, açıkça yönetmek onlarca veya iş parçacığı yüzlerce gitmek için en iyi yol değildir, bazı yetki ile söyleyebiliriz. Bu yapılabilir (yaptım), ama aşırı acı verici.

Bu, dedi. . .

Başvurunuz bence şekilde yazılmışsa, o zaman her iplik böyle bir şey yapar:

while (!Shutdown) 
{ 
    // get next url to crawl from somewhere 
    // download the data from that url 
    // do something with the data 
} 

yüklemeler arasındaki konuları duraklatma oldukça kolaydır. İki ManualResetEvent örneğini yapmanızı öneririm: biri devam etmek için, diğeri ise kapanma için. Tüm paletli iplikleri erişebilmesi böylece bu static şunlardır:

static ManualResetEvent ShutdownEvent = new ManualResetEvent(false); 
static ManualResetEvent ContinueEvent = new ManualResetEvent(true); 

Daha sonra, her bir iplik bir döngüde WaitAny kullanır: I handles dizi tanımlı zaman, ilk ShutdownEvent belirtilen

WaitHandle[] handles = new WaitHandle[] { ShutdownEvent, ContinueEvent }; 
while (true) 
{ 
    int handle = WaitHandle.WaitAny(handles); // wait for one of the events 
    if (handle == -1 || handle >= handles.Length) 
    { 
     throw new ApplicationException(); 
    } 

    if (handles[handle] = ShutdownEvent) 
     break; // shutdown was signaled 

    if (handles[handle] == ContinueEvent) 
    { 
     // download the next page and do something with the data 
    } 
} 

not edin. Bunun nedeni, birden çok öğenin sinyal vermesi durumunda, WaitAny, sinyalli bir nesneye karşılık gelen en düşük endeksi döndürmesidir. Dizi diğer sırada doldurulmuşsa, önce duraklamadan kapanamayacaksınız.

Şimdi, iş parçacığının kapanmasını istiyorsanız, ShutdownEvent.Set numaralı telefonu arayın. Ve iş parçacığının duraklatılmasını istiyorsanız, ContinueEvent.Reset numaralı telefonu arayın. Konuların devam etmesi için, ContinueEvent.Set numaralı telefonu arayın.

Bir indirme işleminin ortasında duraklamak biraz daha zor. Bunu yapmak mümkündür, ancak sorun, çok uzun bir süre duraklatırsanız sunucu zaman aşımı olabilir. Ve sonra indirmeyi en baştan yeniden başlatmanız gerekecek ya da sunucu ve kodunuz destekliyorsa, indirme işlemini bıraktığınız noktadan yeniden başlatın. Her iki seçenek de oldukça acı verici, bu yüzden bir indirme işleminin ortasında durmaya çalışmanızı öneriyorum.

2

uygulama ne yapar yazılım yazıyorum?

500 başlık çok fazla değil - bu yalnızca yığınlar için kararlı bellek olan 1/2 GB. Ve sonra tüm bağlam değiştirmeye sahipsiniz.

Suspend ve Resume çağrılarından kurtulmak istediğinizden emin olun, ancak önce mimarinize bir göz atmanızı öneririm - APM yöntemlerine (BeginXXX/EndXXX) geçebilir misiniz?

+0

Çoğunlukla, bu, web'den bilgi indiren bir ağ uygulamasıdır.Zamanının çoğunu cevapları beklerken harcadığı için, çok iş parçacığı benim için iyi bir fikir gibi görünüyor. Bunu başarmanın daha iyi bir yolunu biliyorsanız, bana bildirin –

2

Söyleyeceklerimle ilgili bir uyarı olarak: Uygulamanızın ne yaptığı açık değil; TPL, arka plan işçileri vb. gibi iş parçacığı havuzu iş parçacığı kullanmak için birçok basit yöntem vardır.

Bununla birlikte, oluşturduğunuz (iş parçacığı değil) iş parçacıklarınız varsa ve bunların iletişim kurmasını istiyorsanız, Monitor.Wait ve Monitor kullanın. Boole engelleme koşulu ile darbe.

ör:

bool _isPaused; 

void DoWork() 
{ 
     while (true) 
     { 
      lock (_locker) 
      { 
       while (_isPaused) Monitor.Wait(_locker); 

       // your worker code here 

      } 

     } 
} 
     // 
void UnPause() 
{ 
     lock (_locker) 
     { 
      _isPaused=false; 
      Monitor.PulseAll(_locker); 
     } 
} 
1

Aslında değil. Askıya Alma/Devam Etme gerçekten basittir ve uygulamanızı kilitleyene kadar iyi çalışır, örn. bellek yöneticisi veya dosya sistemi olan bir iş parçacığının askıya alınmasıyla kilitlenir :(

Normal, biraz daha karmaşık, yaklaşımı, iş parçanızda bekleyebileceğiniz bir yer bulmaktır. iş parçacıklarının normalde bazı IO çağrılarında engellenir ve bu nedenle 'askıya alınır', bu nedenle 'askıya alma' zorlamak için iyi bir yer, okunanların döndüğü yerlerin okunması için okunmanın hemen ardındandır.

Siz @Andrey tarafından önerilen global bir boolean 'isRunning' işaretini denetleyerek fiili askıya alma işlemini yapabilir ve eğer bir askıya alma gerekirse küresel bir ManualResetEvent üzerinde durdu.Makineyi askıya almak, etkinliği temizlemek ve bayrağı kaldırmak için. ve sonra olay:

Eğer globals kullanıyorsanız bulantıyı hissettirirseniz, ctorda flag, event ve 'suspend(),' resume() 've' checkForSuspend() 'yöntemlerini içeren bir sınıfın ortak bir örneğini iletebilirsiniz.

Rgds, Martin

İlgili konular