所以...我正在使用第三方库(zkemkeeper.dll)进行Winform应用程序来管理考勤设备。我正在尝试连接多个设备并附加一些事件,以侦听它们将触发的某些操作。一切正常都可以运行。我运行一些方法,并为每个设备尝试这样连接:
public bool connect(Device myDevice)
{
bool result=false;
if (!myDevice.isConn)
{
myDevice.zkDevice = null;
myDevice.zkDevice = new CZKEMClass();
myDevice.zkDevice.MachineNumber = myDevice.id;
if (myDevice.password.HasValue)
{
myDevice.zkDevice.SetCommPassword(myDevice.password.Value);
}
try
{
result = myDevice.zkDevice.Connect_Net(myDevice.ip, myDevice.port);
myDevice.error = result ? "" : "Could not connect to device";
}
catch (Exception ex)
{
myDevice.error = ex.Message;
result = false;
}
if(result)
{
//Bind events
if (myDevice.zkDevice.RegEvent(myDevice.id, 1))
{
myDevice.zkDevice.OnAttTransactionEx += new _IZKEMEvents_OnAttTransactionExEventHandler(device_OnTransactionEx);
}
}
myDevice.zkDevice.EnableDevice(myDevice.id, true);
myDevice.zkDevice.EnableClock(1);
}
return result;
}
我的主要问题是,这取决于网络的状态,需要花费几秒钟时间才能连接到每个设备,因此,如果我有50或100个设备,则每次连接或重新连接设备时接口都会冻结,并且会造成很大的延迟。(除了该应用程序必须始终可以运行之外)
好了,我要使用它:
private async Task connectAllAsync()
{
List<Task<bool>> lstTasks = new List<Task<bool>>();
foreach (var device in lstDevices)
{
lstTasks.Add(Task.Run(() => connect(device)));
}
var arrayComplete =await Task.WhenAll(lstTasks);
int countErr=arrayComplete.ToList().Where(n => n == false).Count();
if(countErr>0)
{
timerReconnect.Enabled = true;
}
}
此界面不会冻结之后,即使我尝试询问任何设备以获取信息,但设备尝试响应任何未触发的事件时,我对所有设备的连接都会更快。,我不知道我的错误在哪里,我认为这可能与在另一个线程上进行该事件或类似的事件有关。。。谢谢我,给我一些方法。
编辑:我还尝试使“ connect”功能异步,使其等待Connect_Net响应(这是第三方代码的一部分)
答案 0 :(得分:0)
您有未被捕获的closure。试试这个:
foreach (var device in lstDevices)
{
var captured = device;
lstTasks.Add(Task.Run(() => connect(captured)));
}
或者只需使用LINQ即可完成所有操作:
lstTasks = lstDevices.Select
(
device => Task.Run
(
() => connect(device)
)
);
一种完全不同的方法将摆脱Task.Run()
并改用Parallel.ForEach。如果使用这种方法,则必须将结果存储在线程安全的容器中,例如ConcurrentBag<>
。
var results = new ConcurrentBag<bool>();
Parallel.ForEach
(
lstDevices,
device =>
{
results.Add(connect(device));
}
);
int countErr = results.Count( x => x == false );
或者您也可以使用一个计数器:
volatile int countErr = 0;
Parallel.ForEach
(
lstDevices,
device =>
{
var ok = results.Add(connect(device));
if (!ok) Interlocked.Increment(ref countErr);
}
);