private QueueItem NextItem() { if (EnableResourceScheduling) { return(ResourceSections // 各リソース区間の優先度リスト .Select(prs => prs // リソース区間のエントリをリスト化 // リストは優先度の高い順になっていることに注意 .SelectMany(pr => queue[pr]) // リソースキーでまとめる .GroupBy(entry => entry.Key) // リソースキーをコストに変換 // アイテムはそのリソースキーで最も優先度の高いアイテム1つだけにする // アイテムは優先度順になっているはずなのでこれでOK .Select(g => new { Cost = resourceManager.ResourceCost(ReqResource.FromCanonical(g.Key)), Item = g.First().Value.First() }) // リソースの空き具合で並べ替え .OrderBy(g => g.Cost) // 最もリソースの空きの大きいアイテムを選択 // アイテムがない場合nullになることに注意 .FirstOrDefault()?.Item) // 優先度の高い順になっているので最初のアイテムを返す .FirstOrDefault(s => s != null)); } else { return(queue.Reverse() .Select(level => level.FirstOrDefault().Value?.FirstOrDefault()) .FirstOrDefault(s => s != null)); } }
/// <summary> /// リソースを確保する /// </summary> /// <param name="req">次のフェーズで必要なリソース</param> /// <param name="cancelToken">キャンセルトークン</param> /// <returns>確保されたリソース</returns> public async Task <Resource> GetResource(ReqResource req, CancellationToken cancelToken, bool reqEncoderIndex) { var waiting = new WaitinResource() { Req = req }; cancelToken.Register((Action)(() => { waitingResources.Remove(waiting); // キャンセルされたら一旦動かす SignalAll(); }), true); waitingResources.Add(waiting); RecalculateCosts(); while (true) { // リソース確保可能 かつ 最小コスト if (waiting.Cost <= 0 && waiting.Cost <= waitingResources[0].Cost) { waitingResources.Remove(waiting); var res = ForceGetResource(req, reqEncoderIndex); SignalAll(); return(res); } // リソースに空きがないので待つ //Util.AddLog("リソース待ち: " + req.CPU + ":" + req.HDD + ":" + req.GPU); await waitTask.Task; // キャンセルされてたら例外を投げる cancelToken.ThrowIfCancellationRequested(); } }
public int ResourceCost(ReqResource req) { int gpuIndex = MostCapableGPU(); int nextCPU = curCPU + req.CPU; int nextHDD = curHDD + req.HDD; int nextGPU = curGPU[gpuIndex] + req.GPU; return(Math.Max(Math.Max(nextCPU - MAX, nextHDD - MAX), nextGPU - maxGPU[gpuIndex])); }
// 上限を無視してリソースを確保 public Resource ForceGetResource(ReqResource req, bool reqEncoderIndex) { int gpuIndex = MostCapableGPU(); curCPU += req.CPU; curHDD += req.HDD; curGPU[gpuIndex] += req.GPU; RecalculateCosts(); return(new Resource() { Req = req, GpuIndex = gpuIndex, EncoderIndex = reqEncoderIndex ? AllocateEncoderIndex() : -1 }); }
public Resource TryGetResource(ReqResource req, bool reqEncoderIndex) { int cost = ResourceCost(req); if (cost > 0) { // 上限を超えるのでダメ return(null); } if (waitingResources.Count > 0) { // 待っている人がいる場合は、コストが最小値以下でない場合はダメ if (cost > waitingResources[0].Cost) { return(null); } } // OK return(ForceGetResource(req, reqEncoderIndex)); }