c# - 如何在主线程上执行代码直到任务完成
c# - How to execute code on the main thread until a Task finishes
我想更好地了解 TPL。例如,在任务完成之前,我将如何在屏幕上写一些东西。我不能调用 'await' 因为我希望主线程得到通知而不是主动调用 'await' 并且我不想在任务完成之前停止执行。
一些示例代码:
var task = Task.Run(()=>
{
Task.Delay(10000);
});
while(true)
{
Console.WriteLine("Running...");
//I want to exit the loop the second 'task' finishes
//and print 'finished'
}
尝试做这样的事情:
var task = Task.Run(() =>
{
Task.Delay(10000).Wait();
});
bool terminate = false;
while (!task.GetAwaiter().IsCompleted && !terminate)
{
// do something
if (task.GetAwaiter().IsCompleted) break;
// do something heavy
if (task.GetAwaiter().IsCompleted) break;
// do another heavy operation
for (int i = 0; i < 10000; i++)
{
// it took too long!
if (i == 1000)
{
terminate = true;
break;
}
}
}
ContinueWith 函数是任务上可用的方法,允许在任务完成执行后执行代码。简而言之,它允许继续。
这里要注意的是ContinueWith也是returns一个Task。这意味着您可以附加 ContinueWith 一个由此方法返回的任务。
Task<string> t = Task.Run(() => LongRunningOperation("Continuewith", 500));
t.ContinueWith((t1) =>
{
Console.WriteLine("Running...");
});
您可以通过多种方式实现此目的:
首先你可以在 Order 中使用 Lambda 表达式来调用你的操作,但是请看代码:
using System;
using System.Threading;
using System.Threading.Tasks;
public class Example
{
public static void Main()
{
Console.WriteLine("Application thread ID: {0}",
Thread.CurrentThread.ManagedThreadId);
var t = Task.Run(() => { Console.WriteLine("Task thread ID: {0}",
Thread.CurrentThread.ManagedThreadId);
} );
t.Wait();
}
}
// The example displays the following output:
// Application thread ID: 1
//
注意 t.Wait()
:
The call to the Wait
method ensures that the task completes and
displays its output before the application ends. Otherwise, it is
possible that the Main method will complete before the task finishes.
因此我们了解到必须调用 Wait()
方法 以确保任务完成并显示其输出。
你也可以使用第二种方式:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
public class Example
{
public static void Main()
{
var list = new ConcurrentBag<string>();
string[] dirNames = { ".", ".." };
List<Task> tasks = new List<Task>();
foreach (var dirName in dirNames) {
Task t = Task.Run( () => { foreach(var path in Directory.GetFiles(dirName))
list.Add(path); } );
tasks.Add(t);
}
Task.WaitAll(tasks.ToArray());
foreach (Task t in tasks)
Console.WriteLine("Task {0} Status: {1}", t.Id, t.Status);
Console.WriteLine("Number of files read: {0}", list.Count);
}
}
有关更多参考,请参阅 Task.Run Method。
关于您的问题的一个亮点:
取自Asynchronous programming with async and await (C#):
An async method typically contains one or more occurrences of an await
operator, but the absence of await expressions doesn’t cause a
compiler error. If an async method doesn’t use an await
operator to
mark a suspension point, the method executes as a synchronous method
does, despite the async modifier. The compiler issues a warning for
such methods.
这意味着无论哪种方式,您都必须等待任务完成,而主线程将不得不以这种方式或其他方式等待。
您可以通过创建单独的函数在 Task.Run 中使用并通过引用传递参数来实现您的目标。功能应该如下所示。
private void PerformTask(ref bool isComplete)
{
System.Threading.Thread.Sleep(5000);
isComplete = true;
}
从 Task.Run
调用上述函数。您当前的功能应该如下所示。
bool isComplete = false;
System.Threading.Tasks.Task.Run(() => PerformTask(ref isComplete));
while (!isComplete)
{
Console.WriteLine("Running...");
System.Threading.Thread.Sleep(1000);
}
我想更好地了解 TPL。例如,在任务完成之前,我将如何在屏幕上写一些东西。我不能调用 'await' 因为我希望主线程得到通知而不是主动调用 'await' 并且我不想在任务完成之前停止执行。
一些示例代码:
var task = Task.Run(()=>
{
Task.Delay(10000);
});
while(true)
{
Console.WriteLine("Running...");
//I want to exit the loop the second 'task' finishes
//and print 'finished'
}
尝试做这样的事情:
var task = Task.Run(() =>
{
Task.Delay(10000).Wait();
});
bool terminate = false;
while (!task.GetAwaiter().IsCompleted && !terminate)
{
// do something
if (task.GetAwaiter().IsCompleted) break;
// do something heavy
if (task.GetAwaiter().IsCompleted) break;
// do another heavy operation
for (int i = 0; i < 10000; i++)
{
// it took too long!
if (i == 1000)
{
terminate = true;
break;
}
}
}
ContinueWith 函数是任务上可用的方法,允许在任务完成执行后执行代码。简而言之,它允许继续。
这里要注意的是ContinueWith也是returns一个Task。这意味着您可以附加 ContinueWith 一个由此方法返回的任务。
Task<string> t = Task.Run(() => LongRunningOperation("Continuewith", 500));
t.ContinueWith((t1) =>
{
Console.WriteLine("Running...");
});
您可以通过多种方式实现此目的:
首先你可以在 Order 中使用 Lambda 表达式来调用你的操作,但是请看代码:
using System;
using System.Threading;
using System.Threading.Tasks;
public class Example
{
public static void Main()
{
Console.WriteLine("Application thread ID: {0}",
Thread.CurrentThread.ManagedThreadId);
var t = Task.Run(() => { Console.WriteLine("Task thread ID: {0}",
Thread.CurrentThread.ManagedThreadId);
} );
t.Wait();
}
}
// The example displays the following output:
// Application thread ID: 1
//
注意 t.Wait()
:
The call to the
Wait
method ensures that the task completes and displays its output before the application ends. Otherwise, it is possible that the Main method will complete before the task finishes.
因此我们了解到必须调用 Wait()
方法 以确保任务完成并显示其输出。
你也可以使用第二种方式:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
public class Example
{
public static void Main()
{
var list = new ConcurrentBag<string>();
string[] dirNames = { ".", ".." };
List<Task> tasks = new List<Task>();
foreach (var dirName in dirNames) {
Task t = Task.Run( () => { foreach(var path in Directory.GetFiles(dirName))
list.Add(path); } );
tasks.Add(t);
}
Task.WaitAll(tasks.ToArray());
foreach (Task t in tasks)
Console.WriteLine("Task {0} Status: {1}", t.Id, t.Status);
Console.WriteLine("Number of files read: {0}", list.Count);
}
}
有关更多参考,请参阅 Task.Run Method。
关于您的问题的一个亮点:
取自Asynchronous programming with async and await (C#):
An async method typically contains one or more occurrences of an
await
operator, but the absence of await expressions doesn’t cause a compiler error. If an async method doesn’t use anawait
operator to mark a suspension point, the method executes as a synchronous method does, despite the async modifier. The compiler issues a warning for such methods.
这意味着无论哪种方式,您都必须等待任务完成,而主线程将不得不以这种方式或其他方式等待。
您可以通过创建单独的函数在 Task.Run 中使用并通过引用传递参数来实现您的目标。功能应该如下所示。
private void PerformTask(ref bool isComplete)
{
System.Threading.Thread.Sleep(5000);
isComplete = true;
}
从 Task.Run
调用上述函数。您当前的功能应该如下所示。
bool isComplete = false;
System.Threading.Tasks.Task.Run(() => PerformTask(ref isComplete));
while (!isComplete)
{
Console.WriteLine("Running...");
System.Threading.Thread.Sleep(1000);
}