异步问题

nebuung 2020-10-14 03:43:24
insert 插入数据有丢包,感觉是线程阻塞的问题,求正确的异步写法


private void button1_Click(object sender, EventArgs e)
{
try
{
//初始化串口参数
InitSerialPortParameter();
master = ModbusSerialMaster.CreateRtu(port);
ExecuteFunction();
}
catch (Exception)
{
MessageBox.Show("初始化异常");
}
}

private async void ExecuteFunction()
{
String connetStr = "server=10.10.20.5;port=3309;user=root;password=rootqsr; database=db_qualitymanager;";
MySqlConnection conn = new MySqlConnection(connetStr);
try
{
if (port.IsOpen == false)
{
port.Open();
}
if (functionCode != null)
{
switch (functionCode)
{
case "01 Read Coils"://读取单个线圈
//读取线圈
slaveAddress = byte.Parse("1");
startAddress = ushort.Parse("0");
numberOfPoints = ushort.Parse("20");
coilsBuffer = master.ReadCoils(slaveAddress, startAddress, numberOfPoints);
for (int i = 0; i < coilsBuffer.Length; i++)
{
bool m = coilsBuffer[i];//线圈状态
if (m == true)
#region
{
//读取寄存器
int j = i * 4 + 6;
startAddress1 = ushort.Parse(j+"");
numberOfPoints1 = ushort.Parse("3");
registerBuffer = master.ReadHoldingRegisters(slaveAddress, startAddress1, numberOfPoints1);
string x = registerBuffer[0] + "";
string y = registerBuffer[2] + "";
if(x == "0")
{
continue;
}
else
{
if (i < 10)
{
string dpr = "z_0" + i;
conn.Open();
string today = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
string sql = string.Format("insert into "+ dpr +"(vultime,opetime,prdate) values ('{0}','{1}','{2}')", x, y, today);
MySqlCommand cmd = new MySqlCommand(sql, conn);
cmd.ExecuteNonQuery();
conn.Close();

//修改寄存器
string s = j + "";
startAddress = ushort.Parse(s);
string[] strarr = { "0" };
registerBuffer[0] = ushort.Parse(strarr[0]);
await master.WriteSingleRegisterAsync(slaveAddress, startAddress, registerBuffer[0]);
}
else
{
string dpr = "z_" + i;
conn.Open();
string today = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
string sql = string.Format("insert into " + dpr + " (vultime,opetime,prdate) values ('{0}','{1}','{2}')", x, y, today);
MySqlCommand cmd = new MySqlCommand(sql, conn);
cmd.ExecuteNonQuery();
conn.Close();

//修改寄存器
string s = j + "";
startAddress = ushort.Parse(s);
string[] strarr = { "0" };
registerBuffer[0] = ushort.Parse(strarr[0]);
await master.WriteSingleRegisterAsync(slaveAddress, startAddress, registerBuffer[0]);
}

}
#endregion

}
//SetMsg(coilsBuffer[i] + " ");
}
//SetMsg("\r\n");

break;
}

}
else
{
MessageBox.Show("请选择功能码!");
}
port.Close();
}
catch (Exception ex)
{

MessageBox.Show(ex.Message);
}
}
...全文
3775 16 点赞 打赏 收藏 举报
写回复
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
wanghui0380 2020-10-16
线程退出是正常,一个task执行完了,他不退出,难道还占着任务调度和cpu调度么??
  • 打赏
  • 举报
回复
nebuung 2020-10-16
引用 11 楼 wanghui0380 的回复:
你上的图已经说明问题了。

因为每3秒做一次,多次并行会形成并发争抢共享资源“串口”,造成执行顺序混乱,同时当越来越多的task插队,混乱也会越来越严重。

所以问题是“有人插队”,自然解决的手段就是排队
图片是来自不同表的数据,ID当不得真。
我做了断点调试,相应时间远远不到3秒的··
另外我单次点击button时,十多秒后输出窗口会跳线程退出的信息,这个线程怎么看是哪里产生的,会不会是它影响的定时取数
  • 打赏
  • 举报
回复
wanghui0380 2020-10-16
哎,已经说了好几遍了,如果还无法领会,多任务争抢是啥概念,直接上代码,自己运行看看
  public partial class Form1 : Form
    {
        public Form1()
        {
          
           
            InitializeComponent();
        }

        private int i;
        private  void button1_Click(object sender, EventArgs e)
        {
            i++;
            //你会发现啥下面两个方法运行后,你会发现任务是交错进行的任务1,任务2完全是混乱的
            //所以任务1运行完毕有可能会延后很长时间,所以按你的说法就是原本他应该执行,可是他的执行权被其他批次抢了,他永远在等待状态。所以你会发现结果上好像是他掉了
               printTask(i);
           //  await printTask(i);

           //在看改进方案,既然串口并发,当然我们要排队,不能让他们抢任务,一个任务就是一个任务,上一个任务执行完毕才会执行下一个任务,当然就你的东西来说,我们说理论上应该先操作串口再去写db,同时写db可以另外的task里写,尽量不要去占着串口操作时间,毕竟写db这种事情没有查串口那么重要

           printTask1(i);
        }

        public  async Task printTask(int i)
        {
            for (int j = 0; j < 100; j++)
            {
               Trace.WriteLine($"任务{i}-----value:{j}");
                await Task.Delay(100);
            }

        }

        private SemaphoreSlim slim = new SemaphoreSlim(1);
        public async Task printTask1(int i)
        {
            await slim.WaitAsync();
            for (int j = 0; j < 100; j++)
            {
                Trace.WriteLine($"任务改进{i}-----value:{j}");
                await Task.Delay(100);
            }

            slim.Release();

        }
    }
  • 打赏
  • 举报
回复
shawn_yang 2020-10-16
读一个串口为啥需要许多线程?
  • 打赏
  • 举报
回复
nebuung 2020-10-16
引用 13 楼 wanghui0380 的回复:
线程退出是正常,一个task执行完了,他不退出,难道还占着任务调度和cpu调度么??

我意思是它怎么花了10多秒才退出,我怎么看这些线程执行的是什么程序
  • 打赏
  • 举报
回复
wanghui0380 2020-10-15
你上的图已经说明问题了。 因为每3秒做一次,多次并行会形成并发争抢共享资源“串口”,造成执行顺序混乱,同时当越来越多的task插队,混乱也会越来越严重。 所以问题是“有人插队”,自然解决的手段就是排队
  • 打赏
  • 举报
回复
nebuung 2020-10-15
https://download.csdn.net/download/nebuung/12928267
包在这里,请大佬指点一下,实在木有办法了
程序运行的结果是这样子的,除了z08的数据完整外,其他都是缺失的,请教程序怎么改才会避免这种丢失的情况(PS:感应器的通电时间和断开时间之和在5分钟左右)

  • 打赏
  • 举报
回复
wanghui0380 2020-10-15
在你弄不清同步/异步、并行/并发的情况下,别动手 不然那种代码看不得,看着很高级,其实全是坑。
  • 打赏
  • 举报
回复
wanghui0380 2020-10-15
需要控并发。串口只有一个。 至于你说啥丢包,我们只能说丢包到不至于,只是无法保证顺序。 比如你点击3次,那么就是3个task同时在争抢串口操作,系统可以保证你这3个task都可以执行完毕,但不保证3个task的对串口的操作的执行顺序
  • 打赏
  • 举报
回复
派大奇 2020-10-15
简单的异步 楼主 可以了解一下 backgroundWorker C# 这个控件 很简单的异步
  • 打赏
  • 举报
回复
韩老骥 2020-10-14
Button里执行Task.Run,数据库操作部分不要用全局变量。
  • 打赏
  • 举报
回复
nebuung 2020-10-14
引用 1 楼 正怒月神 的回复:
1 要么别用异步。

2 既然用了异步,那button也要异步。
不要同步异步混用。容易死锁。


我看了个简单的异步例子,懂,但是不知道怎么用到我这个实际的需求上···
  • 打赏
  • 举报
回复
nebuung 2020-10-14
引用 2 楼 狂野的小强 的回复:
实在看不出你哪里异步,再说,代码是这么写的么?业务分离,单一原则,兄弟


怎么说呢,我没有系统地学习过C#,就看过一个简单的家庭理财软件视频,不讲基础直接开干的那种,所以很多东西也不明白,现在自学python,对这个也不想深究了,只要能实现功能就好,一般都是简单的需求。

回到正题,我对这个程序做了三秒钟点击一次button1的定时器,去获取PLC中的数据,如果PLC我只连几个点,SQL插入数据是正常的,接的点多了就会丢失,想着大概是因为3秒钟不够执行完for循环里面的内容,所以查到可以用异步,但不会用。
  • 打赏
  • 举报
回复
狂野的小强 2020-10-14
而且mysql插入数据,不可能有丢包哈。
  • 打赏
  • 举报
回复
狂野的小强 2020-10-14
实在看不出你哪里异步,再说,代码是这么写的么?业务分离,单一原则,兄弟
  • 打赏
  • 举报
回复
正怒月神 2020-10-14
1 要么别用异步。 2 既然用了异步,那button也要异步。 不要同步异步混用。容易死锁。
  • 打赏
  • 举报
回复
相关推荐
发帖
C#
加入

10.6w+

社区成员

.NET技术 C#
申请成为版主
帖子事件
创建了帖子
2020-10-14 03:43
社区公告

让您成为最强悍的C#开发者