c# - 永恒的操作多任务
问题描述
我正在研究多任务处理,我想出了一个使用 Windows 窗体的非常简单的解决方案。
我有一个名为“汽车”的对象列表:
public class Car
{
public int Id { get; set; }
public Status Status { get; set; }
}
public enum Status
{
Running,
Standby,
Finished
}
我想在“多会话(任务)”中做一些工作。
因此,假设我的“汽车”有两种方法:StartFullEngine()
并且GoDrive()
我已经在 a 中写入,CarBusiness.cs
并且我想将一些消息输出到richtextbox
. 我有一个 10 辆车的固定列表,会话数将代表上街的汽车数量(几乎同时),但是当它们在街上时,它们总是会做同样的事情。这是:
StartFullEngine()
. 开始后,进入下一步:GoDrive()
. 这可以异步执行,而另一个任务将从列表中选择下一辆车并返回步骤 1。它永远停留在这个循环中,但不会用完会话。
为了实现这一点,这就是我所做的:
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();
}
}
}
当我运行时,这是几秒钟后的输出:(似乎它没有按照我想要的方式运行)。如果这还不够清楚,请告诉我。
启动引擎后,GoDrive()
可以异步运行(无论结束都进入下一次迭代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!
解决方案
推荐阅读
- c# - 如何从 Release 文件夹中打开 .SLN
- sql - 为什么 Oracle ADD_MONTHS() 返回的 sysdate 值与我硬编码今天的日期不同?
- angular - Angular - 如何使用模板中的实用功能
- python - Hstack 不起作用:在文件中插入一列作为第一列
- cypress - 赛普拉斯断言失败,但赛普拉斯 UI 中的测试标记为通过(绿色复选框)。这是预期的吗?
- javascript - 如果数组的任何元素等于 n 或数组的两个元素之和等于 n,则返回 true - 提高性能
- tensorflow - 为什么在计算位置编码时需要将“i”除以 2?
- rabbitmq - 如何在气流中配置代理心跳,以便我可以在 RMQ 管理 UI 的连接选项卡中看到心跳?
- r - 创建映射函数以迭代 API 请求
- javascript - ExpressJS 路由异步中间件