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

C#运行时动态调整Parallel.Invoke操作的实现问题咨询

问题背景

你当前的核心需求是让Parallel.Invoke的入参适配任意数量的已连接设备,避免硬编码3个元素的问题,同时我们也可以顺便优化现有代码里的其他不合理写法。

最佳解决方案

你这里的场景完全不需要用Parallel.Invoke,因为MakePhoneCall.call本身是返回Task<MobileEquipment>的异步方法,属于IO密集型任务,直接用Task.WhenAll处理更简单高效,适配任意数量设备的代码修改如下:

public async Task<String> CallWithEveryConnectedDevice(ListBox listBoxLog, bool sendAlarms)
{        
    const string TEST_CALLS_COMPLETED = "所有测试呼叫已完成";
    const string TEST_CALLS_FAILED = "部分测试呼叫失败";

    List<MobileEquipment> detectedDevicesList = await GetConnectedDevices.getAsync();

    if (detectedDevicesList.Count == 0)
    {
        UpdateGui.listboxAddItem(listBoxLog, "无已连接设备", true);
        return TEST_CALLS_FAILED;
    }

    Console.WriteLine("正在执行测试呼叫...");

    // 直接遍历设备列表生成所有拨号任务,没有数量限制
    List<Task<MobileEquipment>> callTasks = detectedDevicesList
        .Select(device => new MakePhoneCall().call(device, listBoxLog))
        .ToList();

    // 等待所有拨号任务执行完成
    await Task.WhenAll(callTasks);

    // 处理所有返回结果
    foreach (var equipmentTask in callTasks)
    {
        // 用await替代Result避免阻塞和死锁风险
        MobileEquipment equipment = await equipmentTask;
        UpdateGui.listboxAddItem(listBoxLog, 
            $"设备 {equipment.serial}(运营商:{equipment.operador})的测试呼叫结果:{equipment.callSuccess}", 
            true);

        if (!equipment.callSuccess && sendAlarms)
        {                      
            await SendEmail.sendAlarmEmailsAsync(libreta, asunto, mensaje);
        }
    }
                      
    UpdateGui.listboxAddItem(listBoxLog, TEST_CALLS_COMPLETED, true);
    return TEST_CALLS_COMPLETED;
}

原有代码的问题说明

  1. 嵌套Task返回值:原写法async Task<Task<String>>属于不必要的嵌套Task,直接用Task<String>作为返回值即可,也不需要外层套Task.Run。
  2. 线程安全问题:List<T>不是线程安全的集合,你在Parallel.Invoke的多线程委托里直接调用Add方法,可能会出现丢数据、索引异常的问题。
  3. API选型错误:Parallel.Invoke是为CPU密集型并行场景设计的API,你这里的拨号、ADB操作都属于IO密集型任务,用Task.WhenAll更节省线程资源,性能更好。

如果你一定要用Parallel.Invoke的实现方案

如果业务要求必须用Parallel.Invoke,可以按如下方式动态生成Action数组,注意要加锁保证集合操作的线程安全:

List<Task<MobileEquipment>> results = new List<Task<MobileEquipment>>();
// 动态生成Action数组
Action[] invokeActions = detectedDevicesList
    .Select<MobileEquipment, Action>(device => () => 
    {
        // 加锁避免多线程操作List的异常
        lock(results)
        {
            results.Add(new MakePhoneCall().call(device, listBoxLog));
        }
    })
    .ToArray();
Parallel.Invoke(invokeActions);

内容的提问来源于stack exchange,提问作者Felipe La Rotta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 09:06:04