从 TPL foreach 循环修改 class 变量
Modifying class variable from TPL foreach loop
我有以下控制台应用程序,它会从存储帐户容器中删除超过 7 天的 blob。
我正在尝试通过调用 WriteNumberFilesProcessed() 在控制台屏幕上创建一个反馈循环,它会在删除 blob 后递增成员变量 _counter 然后写入控制台。
问题是当最后一个任务在 TPL foreach 循环中完成而不是 _counter 成员变量从 29999 到 30000 时,它会更远一些,即 29995。
我不确定我需要做什么来确保 TPL foreach 循环获得最新的成员变量?
class Program
{
static int _counter = 0;
static int _numBlobsToDelete = 30000;
static int _blobCount = 0;
static void Main(string[] args)
{
GetOldBlobs();
Console.ReadLine();
}
static async void GetOldBlobs()
{
try
{
Stopwatch stopWatch = new Stopwatch();
CloudStorageAccount acc = CloudStorageAccount.Parse("");
var client = acc.CreateCloudBlobClient();
var container = client.GetContainerReference("");
var rollingTotal = 0;
while (true)
{
stopWatch.Restart();
Console.WriteLine($"{DateTime.Now}:\tGetting blobs older than a week in a batch of {_numBlobsToDelete}...");
var blobs = container.ListBlobs("", true).OfType<CloudBlockBlob>().Where(b => (DateTime.UtcNow.AddDays(-7) > b.Properties.LastModified.Value.DateTime)).Take(_numBlobsToDelete).ToList();
_blobCount = blobs.Count();
_counter = 0;
Console.WriteLine($"{DateTime.Now}:\tTime taken to get {_numBlobsToDelete} blobs - {stopWatch.Elapsed}");
Console.WriteLine($"{DateTime.Now}:\tDeleting {_blobCount} blobs...");
try
{
Parallel.ForEach(blobs, blob => DeleteBlob(blob));
}
catch (Exception ex)
{
Console.WriteLine($"{DateTime.Now}:\t{ex.Message}");
}
rollingTotal += _blobCount;
Console.WriteLine($"\n{DateTime.Now}:\tTime taken to delete blobs - {stopWatch.Elapsed}");
Console.WriteLine($"{DateTime.Now}:\t{rollingTotal} blobs deleted since startup");
Console.WriteLine($"{DateTime.Now}:\tSleeping for 5 seconds...\n");
await Task.Delay(5000);
}
}
catch (Exception ex)
{
Console.WriteLine($"{DateTime.Now}:\t{ex.Message}");
}
}
public static void DeleteBlob(CloudBlockBlob blob)
{
try
{
blob.Delete();
WriteNumberFilesProcessed();
}
catch (Exception ex)
{
Console.WriteLine($"{DateTime.Now}:\t{ex.Message}\n");
}
}
public static void WriteNumberFilesProcessed()
{
_counter++;
Console.Write($"\r{_counter} of {_blobCount}");
}
}
您的问题是多个线程同时调用 _counter++
。这会导致竞争条件。
要修复它,最简单的方法是使用 Interlocked
方法之一,如下所示:
Interlocked.Increment(ref _counter);
如果不使用锁定,可能发生的情况是(给定线程 A 和线程 B):
假设 _counter 的值为 1:
Thread A: reads value of _counter -> 1
Thread B: reads value of _counter -> 1
Thread A: adds 1 to the value it read -> 2
Thread B: adds 1 to the value it read -> 2
Thread A: writes value back to _counter -> 2
Thread B: writes value back to _counter -> 2
现在 _counter
的值是 2
,而不是它应该有的值,3
。
我有以下控制台应用程序,它会从存储帐户容器中删除超过 7 天的 blob。
我正在尝试通过调用 WriteNumberFilesProcessed() 在控制台屏幕上创建一个反馈循环,它会在删除 blob 后递增成员变量 _counter 然后写入控制台。
问题是当最后一个任务在 TPL foreach 循环中完成而不是 _counter 成员变量从 29999 到 30000 时,它会更远一些,即 29995。
我不确定我需要做什么来确保 TPL foreach 循环获得最新的成员变量?
class Program
{
static int _counter = 0;
static int _numBlobsToDelete = 30000;
static int _blobCount = 0;
static void Main(string[] args)
{
GetOldBlobs();
Console.ReadLine();
}
static async void GetOldBlobs()
{
try
{
Stopwatch stopWatch = new Stopwatch();
CloudStorageAccount acc = CloudStorageAccount.Parse("");
var client = acc.CreateCloudBlobClient();
var container = client.GetContainerReference("");
var rollingTotal = 0;
while (true)
{
stopWatch.Restart();
Console.WriteLine($"{DateTime.Now}:\tGetting blobs older than a week in a batch of {_numBlobsToDelete}...");
var blobs = container.ListBlobs("", true).OfType<CloudBlockBlob>().Where(b => (DateTime.UtcNow.AddDays(-7) > b.Properties.LastModified.Value.DateTime)).Take(_numBlobsToDelete).ToList();
_blobCount = blobs.Count();
_counter = 0;
Console.WriteLine($"{DateTime.Now}:\tTime taken to get {_numBlobsToDelete} blobs - {stopWatch.Elapsed}");
Console.WriteLine($"{DateTime.Now}:\tDeleting {_blobCount} blobs...");
try
{
Parallel.ForEach(blobs, blob => DeleteBlob(blob));
}
catch (Exception ex)
{
Console.WriteLine($"{DateTime.Now}:\t{ex.Message}");
}
rollingTotal += _blobCount;
Console.WriteLine($"\n{DateTime.Now}:\tTime taken to delete blobs - {stopWatch.Elapsed}");
Console.WriteLine($"{DateTime.Now}:\t{rollingTotal} blobs deleted since startup");
Console.WriteLine($"{DateTime.Now}:\tSleeping for 5 seconds...\n");
await Task.Delay(5000);
}
}
catch (Exception ex)
{
Console.WriteLine($"{DateTime.Now}:\t{ex.Message}");
}
}
public static void DeleteBlob(CloudBlockBlob blob)
{
try
{
blob.Delete();
WriteNumberFilesProcessed();
}
catch (Exception ex)
{
Console.WriteLine($"{DateTime.Now}:\t{ex.Message}\n");
}
}
public static void WriteNumberFilesProcessed()
{
_counter++;
Console.Write($"\r{_counter} of {_blobCount}");
}
}
您的问题是多个线程同时调用 _counter++
。这会导致竞争条件。
要修复它,最简单的方法是使用 Interlocked
方法之一,如下所示:
Interlocked.Increment(ref _counter);
如果不使用锁定,可能发生的情况是(给定线程 A 和线程 B):
假设 _counter 的值为 1:
Thread A: reads value of _counter -> 1
Thread B: reads value of _counter -> 1
Thread A: adds 1 to the value it read -> 2
Thread B: adds 1 to the value it read -> 2
Thread A: writes value back to _counter -> 2
Thread B: writes value back to _counter -> 2
现在 _counter
的值是 2
,而不是它应该有的值,3
。