62,046
社区成员
请大神帮忙看看,有问题的程序是第二段,MethodAsync 传的参数 DataToProtocol类型包含两部分,一部分是ArrayList,一部分是string。经过await后,ArrayList的数据就全没了,数量为0,字符串还在。 这是什么情况?问问题原因是,await中执行的DoSomething中的ArrayList数据也没有,只有字符串。应该如何修改才能让DoSometing能让类的数据不丢失?
public static void GetBack(DataToProtocol msg)
{
WriteToMySQL(msg);
if (MQTTstart == false)
{
MethodAsync(msg);//调用异步方法
}
}
public static async void MethodAsync(DataToProtocol msg)
{
MQTTstart = true;
Console.WriteLine(msg.Data.Count.ToString()+","+msg.SQLTabelname+",111111");
string str = await DoSomething(msg);
Console.WriteLine(msg.Data.Count.ToString()+"," + msg.SQLTabelname+ ",222222222");
MQTTstart =false;
}
static Task<string> DoSomething(DataToProtocol msg)
{
return Task<string>.Run(() =>
{
GetBackFromProtocol(msg);
return "返回值";
});
}
internal class DataToProtocol
{
public ArrayList Data { get; set; } =new ArrayList();
public string SQLTabelname { get; set; }
}
DataToProtocol msg = new DataToProtocol()
{
Data = new ArrayList { 1, 2, 3 },
SQLTabelname = "test"
};
MethodAsync(msg);
同样没有问题,上面这些代码都没有问题。如果说多线程并行,一会有一会没有,我大概猜需要看看这个DataToProtocol了,要是依赖staic静态字段就可以解释你这里出现的问题了
多线程访问的对象为啥不加锁?class DataToProtoco
你提供的信息不足以发现你的bug,因此无法解决任何问题。不仅仅是你修改数据结构、修改参数类型,甚至你不修改数据结构而仅仅修改你测试所传的 ArrayList 数据,可能你也不调试分析抛出异常时的堆栈,而是给出了十足怪异的理论“解释”并且自己也能相信世界上有鬼,甚至千方百计推翻之前的比你得新代码成熟得多的老代码。由此我们看将来的开发环境,在一个小的业余开发团队里,如果不注重实际能力,团队将是非常危险的会彻底走偏。
仅从你的代码来看,你既然使用 async void MethodAsync(....) 来封装一个独立不需要等待的过程,它直接调用 GetBackFromProtocol(msg) 就可以了,这类代码使用一句 await Task.Yield() 语句就能通知 MethodAsync 方法在什么地方编织异步调用代码,而不需要另外封装一个 Task 去调用。当然我还是更注重理念,注重实际调试和测试,(相对)轻视编程语句。
实际去调试你的 bug,一个职业程序员不能说什么“ArrayList不稳定”这类话,顶多只能说“类型不明确,隐藏祸害”这类。你可以随便重新修改 DtaToProtocol 的数据结构,但是你却没能力调试 GetBackFromProtocol 方法,贴不出方法内部的调试截图,由此可见问题实际出处在于内部的堆栈!
例如有些人动不动就写 try......catch代码,即使不考虑异常处理所需要的巨大的性能缺失,也能从代码很容易看出其思维习惯,容易一眼看出可能已经丧失了调试开发能力,只能抄一些代码。“是否调试到位”是个最基础的程序员素质,是专业的开发者最注重的,是起决定性的。
这也是现在社会上很多所谓的“程序员培训基地”那类没有全面的软件的专业基础课的机构的弊害,培养出来的毕业生白花学费,没学到真的知识,仅被忽悠出了糊弄自己的激情。
使用下面对象,模拟调试,没有问题
internal class DataToProtocol
{
public List<int> Data { get; set; } = new List<int>();
public string SQLTabelname { get; set; }
}
public static void GetBack(DataToProtocol msg)
{
WriteToMySQL(msg);
if (MQTTstart == false)
{
MethodAsync(msg);//调用异步方法
}
}
public static async void MethodAsync(DataToProtocol msg)
{
var msg2=msg;
MQTTstart = true;
Console.WriteLine(msg2.Data.Count.ToString()+","+msg2.SQLTabelname+",111111");
string str = await DoSomething(msg2);
Console.WriteLine(msg2.Data.Count.ToString()+"," + msg2.SQLTabelname+ ",222222222");
MQTTstart =false;
}
static Task<string> DoSomething(DataToProtocol msg)
{
var msg1=msg;
return Task<string>.Run(() =>
{
GetBackFromProtocol(msg1);
return "返回值";
});
}
public static void GetBackFromProtocol(DataToProtocol msg)
{
var msg3 = msg;
Console.WriteLine(msg3.Data.Count.ToString() + "," + msg3.SQLTabelname + ",33333333");
System.Threading.Thread.Sleep(3000);
}
1.GetBackFromProtocol(msg);干了啥我们不知道
2.在有委托(闭包)的情况下,尽量不要直接使用方法形参,如果有异步动作直接使用形参,并行执行有可能会参数穿越,所以一般会使用方法内临时变量中介一下
var msg1=msg;
return Task<string>.Run(() =>
{
GetBackFromProtocol(msg1);
return "返回值";
});