Skip to content

Медведев Фома, 2ДЗ#51

Open
Kpokoko wants to merge 5 commits intokontur-courses:masterfrom
Kpokoko:master
Open

Медведев Фома, 2ДЗ#51
Kpokoko wants to merge 5 commits intokontur-courses:masterfrom
Kpokoko:master

Conversation

@Kpokoko
Copy link
Copy Markdown

@Kpokoko Kpokoko commented Feb 23, 2026

No description provided.

Comment on lines +20 to +21
_replicaStatistics[replicaAddress] =
_replicaStatistics[replicaAddress] * ConfidenceFactor + workTime * (1 - ConfidenceFactor);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Здесь несколько операций: чтение по ключу; арифметические операции; запись по ключу.
Если два потока попытаются вызвать метод одновременно, никто не гарантирует, в каком порядке операции исполнятся (например, они одновременно могут прочитать 0, а затем каждый запишет 0.2*workTime, хотя верным бы было 0.8*(0.2*workTime1) + 0.2*workTime2)

Тебе нужен метод ConcurrentDictionary<,>.AddOrUpdate - он принимает делегат и гарантирует, что новое значение будет вычислено от актуального предыдущего, защищая от гонки потоков

(side-note: AddOrUpdate не гарантирует, что делегат будет вызван единожды, он лишь гарантирует, что новое значение будет верным; но конкретно здесь это будет вполне нормальное поведение и можно об этом не думать)

tasks.Add(ProcessRequestAsync(request));
}

var timeoutTask = Task.Delay(timeout).ContinueWith<string>(_ => throw new TimeoutException());
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ContinueWith ни на что не влияет: исключение внутри него, конечно, возникнет, но т.к. ты не делаешь await timeoutTask, оно останется завёрнутым в таску и дальше не вылетит. Ты можешь удалить ContinueWith, ведь ниже, в 33-й строке, у тебя и так есть явный выброс исключения.

Comment on lines +28 to +30
var remainingTime = timeout - timer.Elapsed;
var timeoutForReplica = TimeSpan.FromTicks(remainingTime.Ticks / (sortedReplicas.Length - i));
var timeoutTask = Task.Delay(timeoutForReplica);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remainingTime и timeoutForReplica могут оказаться отрицательными. Task.Delay может или выбросить исключение, или, с маленьким шансом, превратиться в никогда не заканчивающуюся таску

Comment on lines +34 to +35
var requestResult = await Task.WhenAny(task, timeoutTask);
if (requestResult != timeoutTask)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

если requestResult == timeoutTask, то статистика для реплики не обновится

{
_replicasStatistics.UpdateStats(replicaData.Item1, time.TotalMilliseconds);
requests.Remove(result);
return result.Result;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Если все реплики будут тормозить, то соответствующие таски так и останутся в requests, и статистика для них не обновится

Comment on lines +21 to +27
for (var i = 0; i < ReplicaAddresses.Length; ++i)
{
var request = CreateRequest(ReplicaAddresses[i] + "?query=" + query);
tasks.Add(ProcessRequestAsync(request));
}

var timeoutTask = Task.Delay(timeout).ContinueWith<string>(_ => throw new TimeoutException());
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

По-хорошему timeoutTask бы создать до цикла c ProcessRequestAsync. Иначе выходит, что запросы уже какое-то время как отправлены

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants