我想用C#实现一些异步代码,但是我不能写。给我一个提示。
我有4个任务(任务0,任务1,任务2,任务3)。
然后,如何用C#代码实现这些任务?
下面的代码是不完善的,因为任务1和任务3不应是庸俗的。
static Task WholeTask()
{
var tasks = new List<Task>();
tasks.Add(Task0and1());
tasks.Add(Task2and3());
return Task.WhenAll(tasks);
}
static async Task Task0and1()
{
await Task.Run(() => Method0());
await Task.Run(() => Method1());
}
static async Task Task2and3()
{
await Task.Run(() => Method2());
await Task.Run(() => Method3());
}
static void Method0()
{
Thread.Sleep(1000);
Console.WriteLine("task 0 is completed");
}
static void Method1()
{
Console.WriteLine("task 1 starts");
Thread.Sleep(1000);
Console.WriteLine("task 1 is completed");
}
static void Method2()
{
Thread.Sleep(1000);
Console.WriteLine("task 2 is completed");
}
static void Method3()
{
Console.WriteLine("task 3 starts");
Thread.Sleep(1000);
Console.WriteLine("task 3 is completed");
}
static void Main(string[] args)
{
WholeTask().Wait();
}
答案 0 :(得分:1)
我有4个任务
我将这些定义如下,因为更容易看到答案如何工作:
Task Task0();
Task Task1();
Task Task2();
Task Task3();
任务1在任务0之后。任务3在任务2之后。
您可以使用await
组成(链接/链式)任务:
async Task Task0and1()
{
await Task0();
await Task1();
}
async Task Task2and3()
{
await Task2();
await Task3();
}
任务0和任务2可以是并行的。
使用Task.WhenAll
进行异步并发:
var task0and1 = Task0and1();
var task2and3 = Task2and3();
await Task.WhenAll(task0and1, task2and3);
任务1和任务3仅一个接一个地完成,即任务1在任务3之后或任务3在任务1之后。
将SemaphoreSlim
用于异步兼容锁:
private SemaphoreSlim _mutex = new SemaphoreSlim(1);
async Task Task0and1()
{
await Task0();
await _mutex.WaitAsync();
try { await Task1(); }
finally { _mutex.Release(); }
}
async Task Task2and3()
{
await Task2();
await _mutex.WaitAsync();
try { await Task3(); }
finally { _mutex.Release(); }
}
最终代码:
private SemaphoreSlim _mutex = new SemaphoreSlim(1);
async Task Task0and1()
{
await Task0();
await _mutex.WaitAsync();
try { await Task1(); }
finally { _mutex.Release(); }
}
async Task Task2and3()
{
await Task2();
await _mutex.WaitAsync();
try { await Task3(); }
finally { _mutex.Release(); }
}
async Task WholeTask()
{
var task0and1 = Task0and1();
var task2and3 = Task2and3();
await Task.WhenAll(task0and1, task2and3);
}
以上内容仅在您的任务是实际的异步任务时适用。如果您的任务是同步任务,则应该使用上述同步任务。逐步,将是:
我有4个任务
我将这些定义如下:
void Task0();
void Task1();
void Task2();
void Task3();
任务1在任务0之后。任务3在任务2之后。
您可以通过依次调用来构成(链接/链)功能:
void Task0and1()
{
Task0();
Task1();
}
void Task2and3()
{
Task2();
Task3();
}
任务0和任务2可以是并行的。
使用Parallel
或PLINQ进行并行处理。在这种情况下,由于我们要调用两个函数,因此Parallel.Invoke
是自然的选择:
Parallel.Invoke(task0and1, task2and3);
任务1和任务3仅一个接一个地完成,即任务1在任务3之后或任务3在任务1之后。
使用lock
进行互斥:
private object _mutex = new object();
void Task0and1()
{
Task0();
lock (_mutex) { Task1(); }
}
void Task2and3()
{
Task2();
lock (_mutex) { Task3(); }
}
最终代码:
private object _mutex = new object();
void Task0and1()
{
Task0();
lock (_mutex) { Task1(); }
}
void Task2and3()
{
Task2();
lock (_mutex) { Task3(); }
}
void WholeTask()
{
Parallel.Invoke(task0and1, task2and3);
}
答案 1 :(得分:-1)
以下是解决问题所需的构建基块:
答案 2 :(得分:-1)
我认为这对您有用
static void Main(string[] args)
{
var task0 = new Task(WorkWithSleep("task0"));
var task1 = new Task(WorkWithSleep("task1"));
var task2 = new Task(WorkWithSleep("task2"));
var task3 = new Task(WorkWithSleep("task3"));
var after0or2 = Task.WhenAny(task0, task2).ContinueWith(t =>
{
if (if (task0 == t.Result)
{
Task.WhenAll(task2, task1).ContinueWith((tt) => task3.Start());
task1.Start();
}
else
{
Task.WhenAll(task0, task3).ContinueWith((tt) => task1.Start());
task3.Start();
}
});
task0.Start();
task2.Start();
var allwork = Task.WhenAll(task0, task1, task2, task3);
allwork.Wait();
Console.ReadLine();
}
public static Action WorkWithSleep(string name, int wait = 1000)
{
return () =>
{
Console.WriteLine($"Work:{name} STARTED:{DateTime.Now.ToLongTimeString()}");
Thread.Sleep(wait); //This will simulate proccesor work
Console.WriteLine($"Work:{name} ENDED:{DateTime.Now.ToLongTimeString()}");
};
}
您可以玩等待时间,看看这是否是您想要的。但这不是我所建议的,因为在进行处理器密集型工作时,可以通过编写案例特定的代码来完成许多优化,并且如果需要并行化,则可能会花费很长时间,并且每次优化都很重要。
public static async Task MainAsync()
{
var task0 = Task.Run(WorkWithSleep("task0",5000));
var task2 = Task.Run(WorkWithSleep("task2"));
var task0or2 = await Task.WhenAny(task0, task2);
if (task0or2 == task0)
{
WorkWithSleep("task1")(); //No need to do a run since the thred we are on in not buisy. and can just run on the same one
await task2;
WorkWithSleep("task3")();
}
else
{
WorkWithSleep("task3")();
await task0;
WorkWithSleep("task1")();
}
}
编辑:修改条件后进行更改。
EDIT2:从使用可变的IsComplete变为参考检查。
EDIT3:添加了一种正确的异步方法来实现。