Как реализовать такую задачу.
Есть массив и его нужно распечатывать допустим каждую секунду,
Есть некоторая долгая функция, которая должна заполнять этот массив, она в другом потоке или асинхрона, и разумеется за 1 секунду она не успеет к примеру его заполлнить, тогда она должна заполнить столько сколько успела, а на следующей итерации начать с места разрыва.
Вроде задача легкая.
Вот пример, он вообще не работает как ожидаю. Сколько там недочетов. потенциальных ошибок. неверных решений?
static void Main(string[] args)
{
var p = new Program();
Task.Run(() => p.test()).Wait(1 );
while (p.isRun)
{
int n;
n = p.lastInterputIndex == 0 ? p.N : p.lastInterputIndex;
Console.WriteLine("\tPtint");
if (p.latestFrame != null)
for (int i = 0; i < n; i++)
{
Console.WriteLine(p.latestFrame[i]);
}
Thread.Sleep(2000);
}
}
bool isRun = false;
private object lockObj=new();
private int lastInterputIndex=0;
private int[] latestFrame;
private int N=20;
private async Task test()
{
await RenderLoop();
}
private async Task RenderLoop()
{
if (isRun)
return;
isRun = true;
while (isRun)
{
renderCts = new CancellationTokenSource();
var token = renderCts.Token;
var renderTask = Task.Run(() => RenderFrame(token ));
bool complected = await Task.WhenAny(renderTask, Task.Delay(2000 )) == renderTask;
lock (lockObj)
{
latestFrame = renderTask.Result;
if (complected)
{
isRun= false;
}
else
{
renderCts.Cancel(); // Прерываем долгий рендер
}
}
}
}
private int[] RenderFrame(CancellationToken token )
{
int[] arr;
lock (lockObj)
arr =latestFrame?? new int[N];
for (int i=lastInterputIndex; i<arr.Length; i++)
{
arr[i] = i;
if (token.IsCancellationRequested)
{
lastInterputIndex = i+1;
return arr;
}
Thread.Sleep(500);
}
lastInterputIndex = 0;
return arr;
}
Я ожидаю печать по 4 элемента,(ну или 3-5 элементов) и завершение работы. Этого не просиходит.
Функция не завершается, и не печатает как ожидаю!
Иногда завершается. но не допечатывает концовку.
var renderTask = Task.Run(() => RenderFrame(token ));
bool complected = await Task.WhenAny(renderTask, Task.Delay(2000 )) == renderTask;
Вот эта например строчка, как работает функция Task.WhenAny почему она не выполняется так как написано она должна выполнятся, Она должна вернуть первый завершившийся поток. Но она возвращает всегда не то что я ожидаю при том это даже не рандом, это именно то что мне не нужно, сколько не тестирую.
Например если я сделаю
bool complected = await Task.WhenAny(renderTask, Task.Delay( int.MaxValue )) == renderTask;
то очевидно renderTask выполнится быстрее и результат всегда true, но это не проиходит. как и обратное.
Потом программа(но уже не этот код) или поток на этой строчке может завершиться, без ошибок. И это прям смешно, стоит какой-то Console.WriteLine добавить ниже и не завершается.
Потом при дебагинге, на следующию порой строчку, не идет управление, будто зависает, но не зависает.
----------------------------------------------------------------------------------------------------------------------------------------------
Как реализовать разделение отрисовки графики, и вычисления параметров не блокирую интерфейс программы
Похожая функция есть в wpf проекте, там нужно отрисовать часть графики, и если не успела выполнится, то отрисовать то что есть, при этом все должно в минимум в 3 потоках происходить,
- 1 поток интерфейса, туда в OnRender просто нужно вернуть буффер с прошлого кадра отрисовки.
- 2 поток отрисовки, 1 рисует на буффер(элемент, rendertargetbitmap, массив) графику, допустим 10 кругов по 1сек каждый с задержкой
- 3 поток, поток модели, здесь вычисляются характеристики модели, допустим пустая нагрузка, и передается на отрисовку
При том 2 и 3 потоки должны работать одновременно, отрисовывается всегда по вычисленным характиристикам пред кадра, а поток интерфейса получается на целых 2 кадра должен отставать.