//TODO this method cannot be called twice? public async Task <List <PenPack> > Sort(PenPallet penPalletInfo, int penPackSize) { lock (_locker) { IsBusy = true; } await Task.Delay(1); var result = new List <PenPack>(); foreach (var pen in penPalletInfo.PensColorCodes) { if (!PenColorsBuckets.ContainsKey(pen)) { PenColorsBuckets[pen] = 0; } PenColorsBuckets[pen]++; //pack is ready, add it to result if (PenColorsBuckets[pen] == penPackSize) { result.Add(new PenPack() { PackSize = penPackSize, PenColor = pen }); PenColorsBuckets[pen] = 0; } } lock (_locker) { IsBusy = false; } return(await Task.FromResult(result)); }
public async Task <List <PenPack> > Sort(List <PenPallet> penPalletInfo, int penPackSize) { var tasks = new List <Task <List <PenPack> > >(); //моя идея такая. Мы будем кормить сортировщикам максимально большие паллеты. Поиск будет простым проходом, т.е. не очень эффективный. var listCopy = penPalletInfo.Select(t => t).OrderByDescending(t => t.PensColorCodes.Count).ToList(); var listCopyLocker = new object(); var totalPens = 0; while (listCopy.Count > 0) { PenPallet penPallet; lock (listCopyLocker) { penPallet = listCopy.FirstOrDefault(t => t.PensColorCodes.Count <= MaxCapacity - CurrentCapacity); listCopy.Remove(penPallet); } if (penPallet == null) { await Task.Delay(5); continue; } while (Sorters.All(t => t.IsBusy)) { //wait for sorter await Task.Delay(5); } var sorter = Sorters.First(t => !t.IsBusy); lock (_capacityLocker) { totalPens += penPallet.PensColorCodes.Count; CurrentCapacity += penPallet.PensColorCodes.Count; } if (CurrentCapacity > MaxCapacity) { Logger.Warn( $"Table capacity exceeded limit ({MaxCapacity}). Capacity: {CurrentCapacity}"); } var sortTask = sorter.Sort(penPallet, penPackSize).ContinueWith(t => { lock (_capacityLocker) { CurrentCapacity -= penPallet.PensColorCodes.Count; } return(t.Result); }); tasks.Add(sortTask); } Logger.Info($"Total pens sorted on sorting table #{InstanceName}: {totalPens}"); return(await Task.WhenAll(tasks).ContinueWith(sortTask => { //собираем корзинки сортировщиков после того, как отсортировали все карандаши и дособираем из них пачки. //Здесь, для "честности" алгоритма правлиьно было бы отдать карандаши сортировщику. var bucketPallet = new PenPallet { PensColorCodes = new List <int>() }; foreach (var sorter in Sorters) { foreach (var kvp in sorter.PenColorsBuckets) { //собираем псевдо-паллету с количеством карандашей, равным остатку в корзинке сортировщика bucketPallet.PensColorCodes.AddRange(Enumerable.Range(0, kvp.Value).Select(t => kvp.Key)); } sorter.PenColorsBuckets.Clear(); } ; var bucketPacks = Sorters.First().Sort(bucketPallet, penPackSize).Result; var penPacks = sortTask.Result.SelectMany(t => t) .Union(bucketPacks) .ToList(); return penPacks; })); }