C# 从C中的多个异步方法(即线程)中增加值类型#
我需要在C#中增加多个线程(异步方法)的计数器C# 从C中的多个异步方法(即线程)中增加值类型#,c#,multithreading,asynchronous,async-await,C#,Multithreading,Asynchronous,Async Await,我需要在C#中增加多个线程(异步方法)的计数器 我无法传递ref参数,因为它是异步方法 我不能仅仅更新值(或锁定它),因为它是一种值类型 我不能使用Interlocked,因为我不能在async方法中对计数器进行引用 所以我唯一想做的就是做一些傻事,比如列表,然后把我的int放在里面,这样线程就可以锁定列表并更新值 我希望这是一个已知的用例,并且有一种更优雅的方式来实现它 下面是一个小示例,不要管小语法问题: public void DoStuff() { int counter;
- 我无法传递ref参数,因为它是异步方法
- 我不能仅仅更新值(或锁定它),因为它是一种值类型
- 我不能使用Interlocked,因为我不能在async方法中对计数器进行引用
列表
,然后把我的int
放在里面,这样线程就可以锁定列表并更新值
我希望这是一个已知的用例,并且有一种更优雅的方式来实现它
下面是一个小示例,不要管小语法问题:
public void DoStuff()
{
int counter;
var tasks = new List<Task>()
for(int i = 0; i < 10; i++)
{
tasks.Add(AsyncMethod(<SOMETHING>));
}
Task.WaitAll(tasks);
Console.WriteLine("Total: {0}", counter);
}
public async Task AsyncMethod(<SOMETHING>)
{
// Lock if needed by <SOMETHING>
<SOMETHING>+=20;
}
public void DoStuff()
{
整数计数器;
var tasks=新列表()
对于(int i=0;i<10;i++)
{
tasks.Add(AsyncMethod());
}
Task.WaitAll(任务);
WriteLine(“总计:{0}”,计数器);
}
公共异步任务AsyncMethod()
{
//如果需要,请锁定
+=20;
}
我需要创建一个带有int
字段的类,还是C#提供一些现成的东西?我并没有被困在这一点上,只是想事后看看是否有更好的方法。谢谢
对于未来的访客:
共识似乎是创建一个自定义类,如class IntHolder{public int Value{get;set;}}
,可以通过引用传递并锁定(或使用Interlocked-on)
谢谢大家 您可以在任何对象上使用
锁定
,而不仅仅是要使用的对象
例如:
object locking_object = new object();
这将创建一个仅用于锁定的对象
然后,当您要增加值时:
lock(locking_object)
{
integer++;
}
根据评论更新:
创建一个类来保存整数值,如下所示:
class IntHolder
{
public int Value;
}
Interlocked.Increment(ref int_holder.Value);
您可以使用Interlocked
类执行以下操作:
class IntHolder
{
public int Value;
}
Interlocked.Increment(ref int_holder.Value);
其中,
int\u holder
是传递给方法的类型为int holder
的变量的名称。如果希望能够在异步方法之间传递值,或许可以利用:
private asynchlocal counter=new asynchlocal();
公共异步任务fooancy()
{
等待任务;
联锁增量(参考计数器值);
}
我想发布一个完整的代码示例b/c有些事情可能很棘手
public class MyIntIncrementer
{
public int MyInt = 0;
}
public static String TimeStamp
{
get { return DateTime.UtcNow.ToString("HH:mm:ss.fff"); } //yyyy-MM-dd
}
public static void Main(string[] args)
{
List<Task<string>> tasks = new List<Task<string>>();
int waitSeconds = 5;
Console.WriteLine(String.Format("{0}: Start", TimeStamp));
DateTime start = DateTime.Now;
MyIntIncrementer iIncrementer = new MyIntIncrementer();
iIncrementer.MyInt = 0;
for (int i = 0; i < 10; i++)
{
//definitely loops and changes values - but when passed in to the function they don't remain that way... see iParam
//Console.WriteLine(String.Format("{0}: Looping... i: {1}\n", TimeStamp,i));
tasks.Add(Task.Run(() =>
{
// all have 10 => last value :(
// Console.WriteLine(String.Format("{0}: Running... i: {1}\n", TimeStamp, i));
return SayYesIfEven(waitSeconds, i, iIncrementer);
}));
}
Console.WriteLine(String.Format("{0}: Before Wait...", TimeStamp));
// wait for them to run
Task.WhenAll(tasks).Wait();
//Task.WhenAll(tasks); // doesn't wait with .Wait()
Console.WriteLine(String.Format("{0}: After Wait... Results:", TimeStamp));
// get the results
for (int i = 0; i < tasks.Count; i++)
{
Console.WriteLine(tasks[i].Result);
}
Console.WriteLine(String.Format("{0}: Done ({1}s)", TimeStamp, (DateTime.Now - start).TotalSeconds));
}
public static async Task<string> SayYesIfEven(int waitSeconds, int iParam, MyIntIncrementer iIncrementer)
{
int localIParamStart = (int)iParam; // no difference from passed in value when copied locally
int currentIStart = iIncrementer.MyInt; // not guaranteed to be unique
// iParam is the last value and when 'iIncrementer.MyInt' prints here, it's sometimes the same in multiple threads
Console.WriteLine(String.Format("{0:00}: Before Increment: even? {1} <=> {2:00} / iP: {3:00} / LiP: {4:00} / in.mP: {5:00}", TimeStamp, (currentIStart % 2 == 0 ? "Yes" : "No "), currentIStart, iParam, localIParamStart, iIncrementer.MyInt));
// best way to get a unique value
int currentIR = Interlocked.Increment(ref iIncrementer.MyInt); // all threads wait on a lock to increment and then they move forward with their own values
int currentI = iIncrementer.MyInt;
int localIParam = (int)iParam;
Console.WriteLine(String.Format("{0:00}: After Increment: even? {1} <=> {2:00} => {6:00} => {7:00} / iP: {3:00} / LiP: {4:00} => {8:00} / in.mP: {5:00}", TimeStamp, (currentI % 2 == 0 ? "Yes" : "No "), currentIStart, iParam, localIParamStart, iIncrementer.MyInt, currentIR, currentI, localIParam));
await Task.Delay(waitSeconds * 1000); // simulate delay
await Task.Run(() =>
{
// do other stuff...
// iParam and iIncrementer.value have the last value (note that this statement runs after the above delay)
Console.WriteLine(String.Format("{0:00}: Inside Run after Delay: even? {1} <=> {2:00} => {6:00} => {7:00} / iP: {3:00} / LiP: {4:00} => {8:00} / in.mP: {5:00}", TimeStamp, (currentI % 2 == 0 ? "Yes" : "No "), currentIStart, iParam, localIParamStart, iIncrementer.MyInt, currentIR, currentI, localIParam));
return "something";
});
// all have last value when showing what was passed into SayYesIfEven - and iIncrementer.value is also the last value
return (String.Format("{0:00}: Returning: even? {1} <=> {2:00} => {6:00} => {7:00} / iP: {3:00} / LiP: {4:00} => {8:00} / in.mP: {5:00}", TimeStamp, (currentI % 2 == 0 ? "Yes" : "No "), currentIStart, iParam, localIParamStart, iIncrementer.MyInt, currentIR, currentI, localIParam));
}
公共类MyIntIncrementer
{
公共int-MyInt=0;
}
公共静态字符串时间戳
{
获取{return DateTime.UtcNow.ToString(“HH:mm:ss.fff”);}//yyy-mm-dd
}
公共静态void Main(字符串[]args)
{
列表任务=新列表();
整数秒=5;
WriteLine(String.Format(“{0}:Start”,TimeStamp));
DateTime start=DateTime.Now;
MyIntIncrementer IIIncrementer=新的MyIntIncrementer();
iIncrementer.MyInt=0;
对于(int i=0;i<10;i++)
{
//肯定会循环和更改值-但当传递到函数时,它们不会保持这种方式…请参阅iParam
//WriteLine(String.Format(“{0}:Looping…i:{1}\n”,TimeStamp,i));
tasks.Add(Task.Run)(()=>
{
//都有10=>最后一个值:(
//WriteLine(String.Format(“{0}:Running…i:{1}\n”,时间戳,i));
返回sayyesifen(等待秒、i、i增量);
}));
}
WriteLine(String.Format(“{0}:Before Wait…”,TimeStamp));
//等着他们跑
Task.WhenAll(tasks.Wait();
//Task.WhenAll(tasks);//不使用.wait()等待
WriteLine(String.Format(“{0}:After Wait…Results:”,TimeStamp));
//得到结果
for(int i=0;i{6:00}=>{7:00}/iP:{3:00}/LiP:{4:00}=>{8:00}/in.mP:{5:00}”,时间戳,(currentI%2==0?:“是”):“否”),currentIStart,iParam,localIParamStart,iIncrementer.MyInt,currentIR,currentI,localIParam);
等待任务。延迟(waitSeconds*1000);//模拟延迟
等待任务。运行(()=>
{
//做其他事情。。。
//IPRAM和IIIncrementer.value具有最后一个值(请注意,此语句在上述延迟之后运行)
Console.WriteLine(String.Format(“{0:00}:延迟后内部运行:偶数?{1}{2:00}=>{6:00}=>{7:00}/iP:{3:00}/LiP:{4:00}=>{8:00}/in.mP:{5:00}”,时间戳,(currentI%2==0?:“是”):“否”)、currentIStart、iParam、localIParamStart、iIncrementer.MyInt、currentIR、currentI、localIParam);
返回“某物”;
});
//当显示传递到sayyesifeen中的内容时,所有都具有最后一个值,并且iIncrementer.value也是t