You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF中异步函数调用失效问题求助

问题分析与解决方案

首先,你的核心问题出在ExecuteJob方法的循环逻辑、共享变量的线程安全问题上,再结合.NET Framework与.NET Core在内存模型、线程调度的细微差异,加上NuGet打包的潜在兼容性问题,最终导致任务无法正常完成。下面分点拆解并给出解决办法:

1. 共享变量的可见性问题:线程无法感知变量变更

你的ExecuteJob里有两个关键循环:

Do While Me.JobStart = True
    'Warten bis das Startbit von der SPS zurückgesetzt wurde
Loop
_JobIsRunning = True
Do While _JobIsRunning = True
Loop

这里的JobStart和_JobIsRunning都是普通字段,在多线程场景下(你用Task.Run把ExecuteJob放到线程池线程执行),.NET Framework的JIT编译器可能会对这些变量做缓存优化——线程会一直读取本地缓存的变量值,而非内存中的最新值。这就解释了为什么你能看到I/O变量变化,但任务永远卡在循环里无法完成。

解决方案:确保变量的线程可见性

把JobStart和_JobIsRunning声明为Volatile,强制线程每次读取都从内存获取最新值:

<Volatile()> Public Property JobStart As Boolean
<Volatile()> Private _JobIsRunning As Boolean

或者在循环中使用Thread.VolatileRead来读取变量:

Do While Thread.VolatileRead(Of Boolean)(Me.JobStart) = True
Loop

2. 空循环耗尽线程池资源(.NET Framework下更显著)

.NET Framework的线程池调度策略和.NET Core不同,空循环会持续占用线程池线程,既导致CPU空转,也可能让线程无法及时响应变量变更。建议在循环中加入短暂延迟,让出线程资源:

Do While Thread.VolatileRead(Of Boolean)(Me.JobStart) = True
    ' 让出线程,避免CPU占用过高
    Thread.Sleep(10) ' 同步方法中用Thread.Sleep,异步场景可改用Task.Delay
Loop

第二个_JobIsRunning的循环也需要添加同样的延迟逻辑。

3. NuGet打包的兼容性问题

你提到直接引用类库正常,但NuGet安装失效,这大概率是NuGet包没有正确包含.NET Framework 4.7.2的编译输出,或者打包配置有问题。

解决方案:检查并修复NuGet打包配置

  • 确保类库项目的csproj正确声明多目标框架:
<TargetFrameworks>netcoreapp3.1;net472</TargetFrameworks>
  • 使用dotnet pack命令重新打包,确保两个框架的编译输出都被包含进NuGet包。
  • 清理本地NuGet缓存,避免旧缓存文件干扰:
dotnet nuget locals all --clear

4. 简化异常处理逻辑

在ExecuteJobAsync中,你手动检查任务故障并抛出异常的逻辑可以简化——Await会自动传播任务的异常,不需要手动判断:

Public Async Function ExecuteJobAsync() As Task
    Await Task.Run(AddressOf ExecuteJob)
    ' Await会自动抛出任务中的异常,无需手动处理
End Function

验证步骤

  1. 先修改共享变量的可见性并添加循环延迟,直接引用类库到.NET Framework 4.7.2项目测试,确认问题是否解决。
  2. 如果直接引用正常,再重新打包NuGet包、清理缓存后安装测试。

内容的提问来源于stack exchange,提问作者Stef

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 17:27:56