1
for (int i = 1; i < servers.Count;i++){
    var server = new SpeedTestServer(servers[i]);
    server.dist = haversine(server);

    if (closestKnownServer.dist - server.dist > distTreshold){
        closestKnownServer = server;
        this.servers.Add(server);
        this.servers.RemoveAt(0);
    }
    else if (Math.Abs(closestKnownServer.dist - server.dist) <= distTreshold){
        this.servers.Add(server);
        //BUG: we need to enable it but it causes hang
        pingTasks.Add(
            Task.Factory.StartNew(async () => {
                await server.ping();
                if (closestKnownServer.latency > server.latency){
                    closestKnownServer = server;
                    this.servers.RemoveAt(0);
                }
            })
        );
    }

}
await Task.WhenAll(pingTasks);
return closestKnownServer;

看上面的代码。我们创建一个任务列表并填充它。然后我们都等着他们。但它不能正常工作!如果完成,则使用 WhenAll 生成的任务,但它包含的任务不是。如果将断点放入 lambda 和方法的最后一行,则可以看到这一点。

完整代码

PS 我知道我还需要同步,但还没有在 c# 中找到它的内置库。

4

1 回答 1

3

正如 Svick 所评论的,Task.Factory.StartNew与这些差异有不同的重载和功能Task.Run已在此处发布博客:Task.Run vs Task.Factory.StartNew. 结果Task.Factory.StartNew(async () => ...是 a Task<Task>,因此在调用时Task.WhenAll您只需等待外部Task完成。

在上面链接的博客文章的末尾,突出显示了 async 和 await 的区别。对于您的问题,您有三个解决方案:

使用Task.Runwhich 具有隐式异步支持,因此将返回 aTask以执行异步委托。

pingTasks.Add(
    Task.Run(async () => {
        await server.ping();
        if (closestKnownServer.latency > server.latency){
            closestKnownServer = server;
            this.servers.RemoveAt(0);
        }
    })
);

使用将 a变成 a的Unwrap(Task<Task>)扩展方法,在使用更高级的重载时,它正是为此目的而设计的Task<Task>TaskTask.Factory.StartNew

pingTasks.Add(
    Task.Factory.StartNew(async () => {
        await server.ping();
        if (closestKnownServer.latency > server.latency){
            closestKnownServer = server;
            this.servers.RemoveAt(0);
        }
    }).Unwrap()
);

等待其结果Task.Factory.StartNew(async () => ...)将等待外部任务完成,并导致Task执行异步委托。

pingTasks.Add(
    await Task.Factory.StartNew(async () => {
        await server.ping();
        if (closestKnownServer.latency > server.latency){
            closestKnownServer = server;
            this.servers.RemoveAt(0);
        }
    })
);

Task.Run在所有这些中,对于您的情况,由于其隐式异步支持,我建议您使用。

于 2013-12-19T18:54:45.330 回答