将静态变量作为计数器是一个好习惯,可以由C#.NET程序中的所有线程更新吗?
示例代码:
public class SomeTask
{
static int count = 0;
public void Process()
{
while(true)
{
//some repeated task
count++;
if(count>100000)
{
count=0;
break;
}
}
}
}
public class WorkerRole : RoleEntryPoint
{
public override void Run()
{
while(true)
{
for (int i = 0; i < maxTasks; i++)
{
this.Tasks[i] = Task.Factory.StartNew(() => (new SomeTask()).Process());
}
Task.WaitAll(this.Tasks);
//every 100000 in counter needs some updates at program level
}
}
}
答案 0 :(得分:2)
是的,这是一个很好的方法,但要确保使用原子类型。如果使用线程安全代码而不是原子操作来实现计数器增量操作,我会遇到性能问题。
要实施计数器,您将使用++
和--
。通常,这些对C#中的原始类型不是线程安全的。
请参阅Is the ++ operator thread safe?
C#中的原子类型?
参见参考What operations are atomic in C#?
这个答案表明32位机器上32位整数类型是原子的,64位机器上64位整数类型是原子类型。
答案 1 :(得分:2)
如果你无法避免,那就没事了。最好使用Interlocked class递增计数器:
if (Interlocked.Increment(ref counter) % 100000 == 0) {
// Do something every hundred thousand times
// Use "== 1" if you also want to do it on the first iteration
}
如果您只需要知道最后的计数,我会留下以下代码
在您的情况下,您可以将count
保留为实例字段(即非静态),添加公共getter并在所有任务完成后汇总所有计数器:
public class SomeTask
{
int count = 0;
public int Count { get { return count; } }
public void Process()
{
while(true)
{
//some repeated task
count++;
if (something)
break;
}
}
}
var someTasks = new List<SomeTask>();
for (int i = 0; i < maxTasks; i++)
{
var someTask = new SomeTask();
someTasks.Add(someTask);
this.Tasks[i] = Task.Factory.StartNew(() => someTask.Process());
}
Task.WaitAll(this.Tasks);
// Your total count
var total = someTasks.Sum(t => t.Counter);
答案 2 :(得分:0)
是,只要您保持thread-safe
并在线程中同步,它就完全可以了。您可以使用lock进行同步。您可以阅读有关线程安全性和静态成员here和here的更多信息。您还可以使用Interlocked.Increment以线程安全的方式增加计数器。在Eric Lippert answer中通过增量运算符了解有关线程安全的更多信息。
class Account
{
int count;
private Object thisLock = new Object();
public void Add(decimal amount)
{
//your code
lock (thisLock)
{
count = count + 1;
}
}
}