C# - 将同步程序转换为异步程序

Fro*_*Pro 0 c# asynchronous async-await

我目前正在重写我的代码以添加异步执行。但是,我无法适应一组方法。

我看着像几个问题这一个要求,但往往时间之前的问题是使用Task.Run()而不是异步/ AWAIT。

========摘要========

我的程序将用于自动化带有多个阀门的测试台。因此,我编写了open/closeValve()等方法将阀门打开或关闭到某个阈值,增加/减少流量()选择打开或关闭哪个阀门,以及调用 increqse/decreaseFlow()的调节()方法。

就在最近,我在阅读后决定添加异步执行是实时显示有关工作台的数据的好主意。但是我的方法都被认为以同步方式工作,所以我很难适应它们。

========代码======

例如这里是 openValve() 方法

public int openValve(int limit)
    {
        if(_masterFlowrate >= _instructions - 0.1 && _masterFlowrate <= _instructions + 0.1)
        {
            //flowrate ~= instructions => no need to manipulate the valves
            return 1;
        }
        else
        {
            if(valveOpening < limit)
            {
                //flowrate < instructions & valve opened less than the limit
                // => opening valve untill the limit or untill flowrate = instructions
                valveOpening++;
 
                //Opening the valve by writing the value in a command computer via Modbus
                master.WriteSingleRegister(1, _mdbAdr, Convert.ToUInt16(ouvertureValve));
                return 0;
            }
            else
            {
                //flowrate < instructions & valve already opened beyond the limit
                // => not manipulating the valve
                return -1;
            }
        }
Run Code Online (Sandbox Code Playgroud)

适应此方法来异步执行我从改变返回值类型int,以Task<int>及改变return 1return Task.FromResult(1)例如。

现在直接使用前面的increaseFlow()方法是这样的(Vp、Vm和Vg是Valve类的实例)

 public int increaseFlow()
    {
        int retVal = 0;
        switch(openingStep)
        {
            case 1:
                retVal = Vp.openValve(60);
                if(retVal > 0) openingStep = 4;
                else
                {
                    if(retVal < 0) openingStep = 2;
                }
                break;

            case 2:
                retVal = Vg.openValve();
                if(retVal > 0) openingStep = 4;
                else
                {
                    if(retVal < 0) openingStep = 3;
                }
                break;

            case 3:
                retVal = Vm.openValve();
                if(retVal > 0) openingStep = 4;
                else
                {
                    if(retVal < 0) openingStep = 4;
                }
                break;
        }

        return retVal;
    }
Run Code Online (Sandbox Code Playgroud)

这是我开始遇到麻烦的地方。我试过int retVal = 0;改成var retVal = Task.FromResult(0)which 不会给我任何编译器错误。

然后在每个 openValve() 之前添加 awaits 关键字,但这给了我以下内容:

Error   CS0029  Cannot implicitly convert type 'int' to 'System.Threading.Tasks.Task<int>'
Run Code Online (Sandbox Code Playgroud)

然后regulator() 方法调用increaseFlow()。

========结论======

这就是我开始思考的地方,也许代码没有被认为是异步工作的,需要重新排列。这真的是我的问题还是有不需要完全重做这些方法的解决方案。我并不是说我不会这样做,但我很想知道结构是否错误,或者我是否只是没有使用正确的关键字/方法等......

Ste*_*ary 5

添加异步执行是实时显示有关工作台的数据的好主意

这并不是异步执行的真正用途。异步就是释放线程,这在客户端转化为响应式 UI,在服务器端转化为更具可扩展性的服务。

关于“实时显示有关工作台的数据”,听起来您真正想要的是一种进度报告形式。(请注意,此上下文中的“进度”可以是任何数据集合,而不仅仅是完成百分比)。内置程序IProgress<T>是为进度报告而设计的,即使大多数示例都是针对异步代码的,也可以与同步代码完美配合。

如果您的应用主要发出 I/O 绑定请求,您需要异步代码。但是使某些事情异步的正确方法是从最低级别开始,例如,,WriteSingleRegister然后让异步从那里通过应用程序发展。如果您正在控制硬件,异步是可能的,但可能不是最佳解决方案。