Bu kod verildiğinde:
var arrayStrings = new string[1000];
Parallel.ForEach<string>(arrayStrings, someString =>
{
DoSomething(someString);
});
1000 parçacığın tümü neredeyse aynı anda mı ortaya çıkacak?
Bu kod verildiğinde:
var arrayStrings = new string[1000];
Parallel.ForEach<string>(arrayStrings, someString =>
{
DoSomething(someString);
});
1000 parçacığın tümü neredeyse aynı anda mı ortaya çıkacak?
Yanıtlar:
Hayır, 1000 iş parçacığı başlatmayacak - evet, kaç iş parçacığı kullanılacağını sınırlayacaktır. Paralel Uzantılar, fiziksel olarak kaç tane bulunduğunuza ve kaç tanesinin halihazırda meşgul olduğuna bağlı olarak uygun sayıda çekirdek kullanır . İşi her çekirdek için ayırır ve ardından her iş parçacığının kendi kuyruğunu verimli bir şekilde işlemesine izin vermek için iş çalma adı verilen bir teknik kullanır ve yalnızca gerçekten ihtiyaç duyulduğunda pahalı bir çapraz iş parçacığı erişimi yapması gerekir.
Göz at PFX Takım Blog için yükler o işi nasıl tahsis hakkında bilgi ve diğer konular her türlü.
Bazı durumlarda istediğiniz paralellik derecesini de belirtebileceğinizi unutmayın.
Tek çekirdekli bir makinede ... Parallel.ForEach bölümleri (yığınları) üzerinde çalıştığı koleksiyonun bir dizi iş parçacığı arasında çalıştığı, ancak bu sayı hesaba katan ve tarafından yapılan işi sürekli izleyen bir algoritmaya göre hesaplanır. iş parçacıkları ForEach'e tahsis ediyor. Dolayısıyla , ForEach'in vücut kısmı, iş parçacığını beklemede bırakacak uzun süre çalışan IO-bağlı / engelleme işlevlerine çağrı yaparsa, algoritma daha fazla iş parçacığı oluşturur ve koleksiyonu bunlar arasında yeniden bölümlendirir . İş parçacıkları hızlı bir şekilde tamamlanırsa ve örneğin yalnızca bazı sayıları hesaplamak gibi GÇ iş parçacıklarını engellemezse,algoritma, iş parçacığı sayısını, algoritmanın verim için optimum (her yinelemenin ortalama tamamlanma süresi) olarak değerlendirdiği bir noktaya yükseltir (veya gerçekten düşürür) .
Temel olarak, çeşitli Paralel kitaplık işlevlerinin arkasındaki iş parçacığı havuzu, kullanılacak optimum sayıda iş parçacığı belirleyecektir. Fiziksel işlemci çekirdeklerinin sayısı denklemin yalnızca bir bölümünü oluşturur. Çekirdek sayısı ile ortaya çıkan iş parçacığı sayısı arasında basit bir bire bir ilişki YOKTUR.
İş parçacığı senkronizasyonunun iptali ve işlenmesi hakkındaki belgeleri çok yararlı bulmuyorum. Umarım MS, MSDN'de daha iyi örnekler sağlayabilir.
Unutmayın, gövde kodu birden fazla iş parçacığı üzerinde çalışacak şekilde yazılmalıdır, tüm olağan iş parçacığı güvenliği hususları ile birlikte çerçeve bu faktörü henüz soyutlamaz.
İşlemci / çekirdek sayısına bağlı olarak optimum sayıda iş parçacığı oluşturur. Hepsi aynı anda ortaya çıkmayacak.
Bkz. Parallel.For kullanım her yineleme için bir Görev mi? kullanmak için bir "zihinsel model" fikri için. Ancak yazar, "Günün sonunda, uygulama ayrıntılarının her an değişebileceğini hatırlamak önemlidir."
Harika soru. Örneğinizde, dört çekirdekli bir işlemcide bile paralelleştirme düzeyi oldukça düşüktür, ancak biraz beklemekle paralelleştirme düzeyi oldukça yükselebilir.
// Max concurrency: 5
[Test]
public void Memory_Operations()
{
ConcurrentBag<int> monitor = new ConcurrentBag<int>();
ConcurrentBag<int> monitorOut = new ConcurrentBag<int>();
var arrayStrings = new string[1000];
Parallel.ForEach<string>(arrayStrings, someString =>
{
monitor.Add(monitor.Count);
monitor.TryTake(out int result);
monitorOut.Add(result);
});
Console.WriteLine("Max concurrency: " + monitorOut.OrderByDescending(x => x).First());
}
Şimdi bir HTTP isteğini simüle etmek için bir bekleme işlemi eklendiğinde ne olduğuna bakın.
// Max concurrency: 34
[Test]
public void Waiting_Operations()
{
ConcurrentBag<int> monitor = new ConcurrentBag<int>();
ConcurrentBag<int> monitorOut = new ConcurrentBag<int>();
var arrayStrings = new string[1000];
Parallel.ForEach<string>(arrayStrings, someString =>
{
monitor.Add(monitor.Count);
System.Threading.Thread.Sleep(1000);
monitor.TryTake(out int result);
monitorOut.Add(result);
});
Console.WriteLine("Max concurrency: " + monitorOut.OrderByDescending(x => x).First());
}
Henüz herhangi bir değişiklik yapmadım ve eşzamanlılık / paralellik düzeyi dramatik bir şekilde sıçradı. Eşzamanlılık limiti ile artırılabilir ParallelOptions.MaxDegreeOfParallelism
.
// Max concurrency: 43
[Test]
public void Test()
{
ConcurrentBag<int> monitor = new ConcurrentBag<int>();
ConcurrentBag<int> monitorOut = new ConcurrentBag<int>();
var arrayStrings = new string[1000];
var options = new ParallelOptions {MaxDegreeOfParallelism = int.MaxValue};
Parallel.ForEach<string>(arrayStrings, options, someString =>
{
monitor.Add(monitor.Count);
System.Threading.Thread.Sleep(1000);
monitor.TryTake(out int result);
monitorOut.Add(result);
});
Console.WriteLine("Max concurrency: " + monitorOut.OrderByDescending(x => x).First());
}
// Max concurrency: 391
[Test]
public void Test()
{
ConcurrentBag<int> monitor = new ConcurrentBag<int>();
ConcurrentBag<int> monitorOut = new ConcurrentBag<int>();
var arrayStrings = new string[1000];
var options = new ParallelOptions {MaxDegreeOfParallelism = int.MaxValue};
Parallel.ForEach<string>(arrayStrings, options, someString =>
{
monitor.Add(monitor.Count);
System.Threading.Thread.Sleep(100000);
monitor.TryTake(out int result);
monitorOut.Add(result);
});
Console.WriteLine("Max concurrency: " + monitorOut.OrderByDescending(x => x).First());
}
Ayarı tavsiye ederim ParallelOptions.MaxDegreeOfParallelism
. Bu, kullanımdaki iş parçacığı sayısını artırmayacaktır, ancak yalnızca mantıklı sayıda iş parçacığı başlatmanızı sağlayacaktır, bu da sizin endişeniz gibi görünüyor.
Son olarak sorunuzu yanıtlamak için, hayır, tüm ileti dizilerinin aynı anda başlamasını sağlayamazsınız. Parallel.Invoke'u, mükemmel şekilde paralel olarak çağırmak istiyorsanız, örneğin yarış koşullarını test etmek istiyorsanız kullanın.
// 636462943623363344
// 636462943623363344
// 636462943623363344
// 636462943623363344
// 636462943623363344
// 636462943623368346
// 636462943623368346
// 636462943623373351
// 636462943623393364
// 636462943623393364
[Test]
public void Test()
{
ConcurrentBag<string> monitor = new ConcurrentBag<string>();
ConcurrentBag<string> monitorOut = new ConcurrentBag<string>();
var arrayStrings = new string[1000];
var options = new ParallelOptions {MaxDegreeOfParallelism = int.MaxValue};
Parallel.ForEach<string>(arrayStrings, options, someString =>
{
monitor.Add(DateTime.UtcNow.Ticks.ToString());
monitor.TryTake(out string result);
monitorOut.Add(result);
});
var startTimes = monitorOut.OrderBy(x => x.ToString()).ToList();
Console.WriteLine(string.Join(Environment.NewLine, startTimes.Take(10)));
}