Я изучаю многозадачность, и я пришел к очень простому решению, используя windows форму.
У меня есть список объектов с именем "Автомобиль":
public class Car
{
public int Id { get; set; }
public Status Status { get; set; }
}
public enum Status
{
Running,
Standby,
Finished
}
, и я хочу поработать в "мультисессиях (задачах)" .
Итак, скажем, у моего "Автомобиля" есть два метода: StartFullEngine()
и GoDrive()
, которые я записал в CarBusiness.cs
, и я хочу вывести некоторые сообщения в richtextbox
. У меня есть фиксированный список из 10 автомобилей, и количество сессий будет представлять количество автомобилей, идущих на улицу (почти в одно и то же время), но когда они находятся на улице, они всегда будут делать одно и то же. Что:
StartFullEngine()
. После запуска, go до следующего шага: GoDrive()
. который может выполняться асинхронно, в то время как другая задача выберет следующий автомобиль из списка и вернется к шагу 1. Он остается в этом l oop навсегда, но без сессий.
Для достижения вот что я сделал:
CarBusiness.cs:
public class CarBusiness
{
private RichTextBox _richTextBox;
private static readonly object syncLock = new object();
private Car _carToRun;
private Random random;
public CarBusiness(Car car, RichTextBox richTextBox)
{
_carToRun = car;
_richTextBox = richTextBox;
random = new Random();
}
private void OutputMessage(string msg)
{
lock (syncLock)
{
_richTextBox.BeginInvoke((Action)(() =>
{
_richTextBox.AppendText($"#{_carToRun.Id}: [{DateTime.Now.Hour.ToString("D2")}:{DateTime.Now.Minute.ToString("D2")}:{DateTime.Now.Second.ToString("D2")}] - {msg}\r\n");
}));
}
}
public Task StartFullEngine()
{
return Task.Run(async () =>
{
var start = DateTime.Now;
await Task.Delay(random.Next(1000, 10000));
var end = DateTime.Now;
TimeSpan timeDiff = start - end;
var readableDiff = string.Format(
"{0:D2} hrs, {1:D2} mins, {2:D2} secs",
timeDiff.Hours, timeDiff.Minutes, timeDiff.Seconds);
OutputMessage($"Full engined finished. Time ellapsed: {readableDiff}");
});
}
public Task GoDrive()
{
return Task.Run(async () =>
{
var start = DateTime.Now;
await Foo();
Boo().Wait();
var end = DateTime.Now;
TimeSpan timeDiff = start - end;
var readableDiff = string.Format(
"{0:D2} hrs, {1:D2} mins, {2:D2} secs",
timeDiff.Hours, timeDiff.Minutes, timeDiff.Seconds);
OutputMessage($"GoDrive() finished. Time ellapsed: {readableDiff}");
});
}
private Task Foo()
{
return Task.Run(async () =>
{
//long operation
OutputMessage($"Running Foo()...");
await Task.Delay(random.Next(1000, 3000));
OutputMessage($"Foo() ended!");
});
}
private Task Boo()
{
return Task.Run(async () =>
{
OutputMessage($"Running Boo()...");
await Task.Delay(random.Next(10000, 30000));
OutputMessage($"Boo() ended!");
});
}
}
CarDao.cs:
public class CarDao
{
public List<Car> GetListOfCar()
{
var list = new List<Car>();
for (int i = 1; i <= 10; i++)
list.Add(new Car { Id = i, Status = Status.Standby });
return list;
}
}
Form1.cs:
public partial class Form1 : Form
{
private List<Car> listOfCars;
private object objInstances = new object();
public Form1()
{
InitializeComponent();
}
private Task<Car> GetNextCar()
{
return Task.Run(() =>
{
lock (objInstances)
{
//Need a logic to prioritize getting cars that have never "run" before
var nextCar = listOfCars.Where(x => x.Status != Status.Running).SkipWhile(x => x.Status == Status.Finished).FirstOrDefault();
return nextCar;
}
});
}
private Task<List<Car>> GetInstances(Status statusCar)
{
return Task.Run(() =>
{
lock (objInstances)
{
return listOfCars.Where(x => x.Status == statusCar).ToList();
}
});
}
private async void button1_Click(object sender, EventArgs e)
{
var carDao = new CarDao();
//NumericUpDown value
var maxSessions = numberOfSessions.Value;
//fixed list of cars
listOfCars = carDao.GetListOfCar();
//Never stop running
while (true)
{
var runningInstances = GetInstances(Status.Running).Result;
for (int i = runningInstances.Count(); i < maxSessions; i++)
{
var carToRun = GetNextCar().Result;
carToRun.Status = Status.Running;
var carBusiness = new CarBusiness(carToRun, richTextBox);
Task.Run(() =>
{
//First thing: StartFullEngine()
carBusiness.StartFullEngine().Wait();
}).Wait();
//After started Engine, GoDrive() can run asynchronously.
await Task.Run(() =>
{
carBusiness.GoDrive().Wait();
carToRun.Status = Status.Finished;
});
//Next loop;
}
//logic to wait some tasks get done to start again
runningInstances = GetInstances(Status.Running).Result;
if (runningInstances.Count() == maxSessions)
Task.Delay(20000).Wait();
}
}
}
и когда я бегу, это вывод через пару секунд: (кажется, что он работает не так, как я хочу). Дайте мне знать, если это недостаточно ясно.
После запуска Engine GoDrive()
может работать асинхронно (go до следующей итерации независимо от конец GoDrive()
).
Я ожидаю что-то вроде этого:
#1: [00:23:27] - Full engined finished. Time ellapsed: 00 hrs, 00 mins, -05 secs
//Once finished, it starts another task. (this case car #2). Now we have two tasks running, so we will until one of them finishes then get another car.
#1: [00:23:27] - Running Foo()...
#1: [00:23:29] - Foo() ended!
#2: [00:23:29] - Full engined finished. Time ellapsed: 00 hrs, 00 mins, -02 secs
#2: [00:23:29] - Running Foo()...
#1: [00:23:29] - Running Boo()...
#2: [00:23:31] - Running Boo()...
#2: [00:23:32] - Boo() ended!
#1: [00:23:52] - Boo() ended!
#1: [00:24:15] - GoDrive() finished. Time ellapsed: 00 hrs, 00 mins, -25 secs
//Now we have finished one task. Go to another (car #3)
#2: [00:24:16] - GoDrive() finished. Time ellapsed: 00 hrs, 00 mins, -16 secs
//Now we have finished one task. Go to another (car #4)
#3: [00:24:20] - Full engined finished. Time ellapsed: 00 hrs, 00 mins, -05 secs
#3: [00:24:21] - Running Foo()...
#3: [00:24:25] - Foo() ended!
#4: [00:23:27] - Full engined finished. Time ellapsed: 00 hrs, 00 mins, -05 secs
#3: [00:24:29] - Running Foo()...
#4: [00:23:29] - Running Boo()...
#4: [00:23:31] - Boo() ended!