如何解决挂起c#的任务?

如何解决挂起c#的任务?,c#,.net,task-parallel-library,C#,.net,Task Parallel Library,在查看控制台应用程序中的一些代码时,我在SecondInitialize函数中看到了嵌套的Task.whall。我决定用一个大的位置列表来测试这个函数,看看它的反应如何 我看到的是,大约有100个位置,100*100=10000Calculate调用,Start内部的t.Wait()大约需要60秒才能返回,有时甚至完全挂起。如果我尝试单击Break All,控制台应用程序甚至不会响应我的单击,visual studio就会崩溃 在SecondInitialize中使用我的“易读版本”时,返回也需

在查看控制台应用程序中的一些代码时,我在
SecondInitialize
函数中看到了嵌套的Task.whall。我决定用一个大的位置列表来测试这个函数,看看它的反应如何

我看到的是,大约有100个位置,100*100=10000
Calculate
调用,
Start
内部的
t.Wait()
大约需要60秒才能返回,有时甚至完全挂起。如果我尝试单击
Break All
,控制台应用程序甚至不会响应我的单击,visual studio就会崩溃

SecondInitialize
中使用我的“易读版本”时,返回也需要一段时间。一贯的行为

奇怪的是,每当我使用调试器,在
SecondInitialize
中设置断点,然后点击continue,它将在5-7秒内完成

所以我的问题是,当我在函数内部调试时看到它更快时,为什么它正常地挂起要花很长时间?另一个问题是
任务的使用是否正确

public void Start()
{
    var t = CacheInitialize(locations, CancellationToken.None);
    t.Wait();
}

public Task CacheInitialize(IList<Location> locations, CancellationToken token)
{
    return SecondInitialize(locations, token);
}

public async Task SecondInitialize(IList<Location> locations, CancellationToken token)
{
    await Task.WhenAll(locations.Select(first =>
    {
        return Task.WhenAll(locations.Where(second => !second.Equals(first)).Select(second =>
        {
            return Calculate(first, second, token);
        }));
    }));

    //Easier to read version of ^
    //var tasks = locations.SelectMany(first => locations.Where(second => !second.Equals(first)).Select(second =>
    //{
    //  return Calculate(first, second, token);
    //}));
    //await Task.WhenAll(tasks);


    //No Tasks.
    //for (int x = 0; x < locations.Length; x++)
    //{
    //    for (int y = 0; y < locations.Length; y++)
    //    {
    //        if (x == y)
    //            continue;
    //        await Calculate(locations[x], locations[y], token).ConfigureAwait(false);
    //    }
    //}
}

public async Task<TripLength> Calculate(Location start, Location finish, CancellationToken token)
{
    if (start == finish)
        return TripLength.Zero;

    var parameters = new RouteParameters
    {
        Coordinates = new []
        {
            new Coordinate(start.Latitude, start.Longitude),
            new Coordinate(finish.Latitude, finish.Longitude)
        }
    };

    var route = await RunRoute(parameters, token);

    return ToTripLength(route);
}


protected Task<RouteResult> RunRoute(RouteParameters routeParams, CancellationToken token)
{
    return Task.Run(async () =>
    {
        var routingTask = Task.Run(() =>
        {
            RouteResult routeResults;
            var status = _routeService.Route(routeParams, out routeResults);
            return routeResults;
        }, token);
    return await routingTask.ConfigureAwait(false);

    }, token);
}
public void Start()
{
var t=CacheInitialize(位置,CancellationToken.None);
t、 等待();
}
公共任务缓存初始化(IList位置、CancellationToken令牌)
{
返回第二次初始化(位置、令牌);
}
公共异步任务SecondInitialize(IList位置、CancellationToken令牌)
{
等待任务。何时(地点)。选择(第一个=>
{
返回Task.WhenAll(locations.Where(second=>!second.Equals(first))。选择(second=>
{
返回计算(第一、第二、令牌);
}));
}));
//易于阅读的版本^
//var tasks=locations.SelectMany(第一个=>locations.Where(第二个=>!第二个.Equals(第一个)).Select(第二个=>
//{
//返回计算(第一、第二、令牌);
//}));
//等待任务。何时(任务);
//没有任务。
//对于(int x=0;x
{
var routingTask=Task.Run(()=>
{
RouterResult RouterResults;
var状态=_routeService.Route(routeParams,out routeResults);
返回路由结果;
},代币);
返回Wait routingTask.ConfigureWait(false);
},代币);
}

由于您的示例不完整且无法编译,因此很难看到您到底在做什么

但据我所知,有几个问题:

  • 对任务调用
    Wait
    (或
    Result
    )。 使用
    ConfigureAwait(false)
    将有助于避免此类问题,但不能消除所有问题。 所以,当您想要访问任务的结果时,最好总是等待任务

  • 我看不出您试图通过在
    Task.WhenAll
    中嵌套
    Task.WhenAll
    来完成什么。
    WhenAll
    返回一个任务,您可以在没有任务的情况下等待它。WhenAll
  • 。 您创建的每个任务都会增加一些性能开销,因此您应该尝试创建尽可能少的任务

  • 使用带有异步委托的
    Task.Run
    等待另一个任务(由
    Task.Run
    创建)毫无意义,因为您创建的任务超过了您的需要。 你可以只等待一个任务。运行

  • 我试图根据您的代码创建一个工作示例(它不会做任何工作),以显示您应该更改什么。 请注意,async Main方法仅在C#7.1或更高版本中可用

    public class Program
    {
        public static async Task Main( String[] args )
        {
            var foo = new Foo();
    
            var sw = Stopwatch.StartNew();
    
            await foo.Start();
    
            sw.Stop();
    
            Console.WriteLine($"Elapsed {sw.Elapsed} {sw.ElapsedMilliseconds}ms");
            Console.ReadLine();
        }
    }
    
    public class Foo
    {
        public async Task CacheInitialize( IList<Location> locations, CancellationToken token ) =>
            await SecondInitialize( locations, token )
                .ConfigureAwait( false );
    
        public async Task<TripLength> Calculate( Location start, Location finish, CancellationToken token )
        {
            if ( start == finish )
                return TripLength.Zero;
    
            var parameters = new RouteParameters
            {
                Coordinates = new[]
                {
                    new Coordinate( start.Latitude, start.Longitude ),
                    new Coordinate( finish.Latitude, finish.Longitude )
                }
            };
    
            var route = await RunRoute( parameters, token );
    
            return new TripLength();
        }
    
        public async Task SecondInitialize( IList<Location> locations, CancellationToken token )
        {
            var tasks = new List<Task>( locations.Count );
    
            foreach ( var outer in locations )
            foreach ( var inner in locations )
            {
                if ( inner.Equals( outer ) )
                    continue;
    
                tasks.Add( Calculate( outer, inner, token ) );
            }
    
            await Task.WhenAll( tasks );
        }
    
        public async Task Start()
        {
            var locations = new List<Location>();
            await CacheInitialize( locations, CancellationToken.None )
                .ConfigureAwait( false );
        }
    
        protected async Task<RouteResult> RunRoute( RouteParameters routeParams, CancellationToken token )
        {
            return await Task
                         .Run( () =>
                               {
                                   //RouteResult routeResults;
                                   //var status = _routeService.Route( routeParams, out routeResults );
                                   //return routeResults;
                                   return new RouteResult();
                               },
                               token )
                         .ConfigureAwait( false );
        }
    }
    
    public class Coordinate
    {
        public Double Latitude { get; }
        public Double Longitude { get; }
        public Coordinate( Double latitude, Double longitude )
        {
            Latitude = latitude;
            Longitude = longitude;
        }
    }
    public class RouteParameters
    {
        public Coordinate[] Coordinates { get; set; }
    }
    public class TripLength
    {
        public static TripLength Zero = new TripLength();
    }
    public class RouteResult
    {
    }
    public class Location
    {
        public Double Latitude { get; }
        public Double Longitude { get; }
    }
    
    公共类程序
    {
    公共静态异步任务主(字符串[]args)
    {
    var foo=new foo();
    var sw=Stopwatch.StartNew();
    等待foo.Start();
    sw.Stop();
    WriteLine($“经过的{sw.eassed}{sw.elapsedmillesons}ms”);
    Console.ReadLine();
    }
    }
    公开课Foo
    {
    公共异步任务缓存初始化(IList位置,CancellationToken令牌)=>
    等待第二次初始化(位置、令牌)
    .配置等待(错误);
    公共异步任务计算(位置开始、位置完成、取消令牌)
    {
    如果(开始==完成)
    返回三倍长度。零;
    var参数=新的路由参数
    {
    坐标=新[]
    {
    新坐标(起点、纬度、起点、经度),
    新坐标(终点、纬度、终点、经度)
    }
    };
    var route=等待运行路由(参数、令牌);
    返回新的三倍长度();
    }
    公共异步任务SecondInitialize(IList位置、CancellationToken令牌)
    {
    var任务=新列表(locations.Count);
    foreach(外部位置的var)
    foreach(位置中的内部变量)
    {
    if(内部等于(外部))
    持续
    添加(计算(外部、内部、令牌));
    }
    等待任务。何时(任务);
    }
    公共异步任务启动()
    {
    变量位置=新列表();
    等待缓存初始化(位置,CancellationToken.None)
    .配置等待(错误);
    }
    受保护的异步任务运行路由(RouteParameters routeParams,Ca
    
    var combinations=( from start in locations
                       from finish in locations
                       where start!=finish
                       select (start,finish))
                     .ToArray();
    
    RouteParameters locationsToParams((Location start,Location finish) combination)
    {
        return new RouteParameters {
            Coordinates = new[]
            {
                new Coordinate( start.Latitude, start.Longitude ),
                new Coordinate( finish.Latitude, finish.Longitude )
            }
        };
    }
    
    RouteResult  callRoute(RouteParameters routeParams)
    {
        _routeService.Route(routeParams, out var routeResults);
        return routeResults;
    }
    
    var tripLengths = from cmb in combinations.AsParallel()
                      let routeParams=locationsToParams(cmb)
                      let result=callRoute(routeParams)
                      select ToTripLength(result);
    var finalResults = tripLengths.ToArray();
    
    var tripLengths = from cmb in combinations.AsParallel()
                                              .WithDegreeOfParalellism(10)
                      let routeParams=locationsToParams(cmb)
                      let result=callRoute(routeParams)
                      select ToTripLength(result);
    var finalResults = tripLengths.ToArray();