我了解异步/等待的基本原理,但是我看到它提到了很多等待不会创建新线程。我可以尊重这一点,因为waits可以使用硬盘I / O或网卡或CPU以外的其他不需要新线程的东西。
我想澄清的是,在等待完成后,异步函数的其余部分是否在新线程上执行?从我自己的内部测试中可以看出,它是按照以下代码执行的:
public static class Program
{
private static void Main(string[] args)
{
Thread.CurrentThread.Name = "ThisThread";
AnAsyncMethod();
while (true)
{
print("External While loop. Current Thread: " + Thread.CurrentThread.Name);
Thread.Sleep(200);
}
}
public static async void AnAsyncMethod()
{
for (int i = 0; i < 10; i++)
{
FakeWork();
print("doing fake pre-await work. Current Thread: " + Thread.CurrentThread.Name);
}
await Task.Run(FakeWork);
for (int i = 0; i < 10; i++)
{
FakeWork();
print("doing fake post-await work. Current Thread: " + Thread.CurrentThread.Name);
}
print("hello");
}
public static void FakeWork()
{
Thread.Sleep(100);
}
}
从这个例子来看,异步方法中似乎使用了相同的线程,直到它遇到第一个wait,此时控制权返回给调用者,程序继续。当wait完成时,一个新的单独线程将在异步方法中继续前进,而不是封送早期的线程并强制它继续自己。这个新线程与现在在其他地方使用的早期线程同时执行。
这是正确的吗?
我已修改您的代码以显示线程ID。
class Program
{
static void Main(string[] args)
{
System.Threading.Thread.CurrentThread.Name = "ThisThread";
AnAsyncMethod();
while (true)
{
Console.WriteLine("External While loop. Current Thread: " + $"{System.Threading.Thread.CurrentThread.Name}- {System.Threading.Thread.CurrentThread.ManagedThreadId}");
System.Threading.Thread.Sleep(200);
}
}
public static async void AnAsyncMethod()
{
for (int i = 0; i < 10; i++)
{
FakeWork();
Console.WriteLine("doing fake pre-await work. Current Thread: " + $"{System.Threading.Thread.CurrentThread.Name}- {System.Threading.Thread.CurrentThread.ManagedThreadId}");
}
await System.Threading.Tasks.Task.Run(FakeWork);// Task.Run(FakeWork);
for (int i = 0; i < 10; i++)
{
FakeWork();
Console.WriteLine("doing fake post-await work. Current Thread: " + $"{System.Threading.Thread.CurrentThread.Name}- {System.Threading.Thread.CurrentThread.ManagedThreadId}");
}
Console.WriteLine("hello");
}
public static void FakeWork()
{
System.Threading.Thread.Sleep(100);
StackTrace stackTrace = new StackTrace();
Console.WriteLine($"Caller of Fakework method is {stackTrace.GetFrame(1).GetMethod().Name}. Current Thread: " + $"{System.Threading.Thread.CurrentThread.Name}- {System.Threading.Thread.CurrentThread.ManagedThreadId}");
}
}
现在,您将在单独的线程中获取帖子等待。现在发生这种情况是因为
当它调用 Task.Run 时,它会将线程池上昂贵的 CPU 密集型操作 Fakework() 排队,并接收 Task 句柄。Fakework() 最终在下一个可用线程上并发运行
有关更多参考资料,请阅读“cpu绑定方法的异步”
https://docs.microsoft.com/en-us/dotnet/standard/async-in-depth
因此,异步等待作业是在线程池上调度任务,并基于默认调度算法,它将使用相同的线程或派生出新的线程
控制台应用程序上的行为与 WinForms 应用程序上的行为不同。
在控制台应用程序上,默认情况下,延续在默认的TaskScheduler上运行,该调度器在可用的工作线程池上运行任务的延续。在WinForms中,这种情况不会发生,因为在WinForm中,延续被发布回UI线程。
考虑以下示例:
static async Task DoSomeThingAsync(string name)
{
Console.WriteLine($"{name} is starting on thread {Thread.CurrentThread.ManagedThreadId}");
for (int i = 0; i < 5; i++)
{
await Task.Delay(1000);
Console.WriteLine($"{name} is now on thread {Thread.CurrentThread.ManagedThreadId}");
}
}
static async Task Main(string[] args)
{
var task1 = DoSomeThingAsync("Harry");
var task2 = DoSomeThingAsync("Fred");
var task3 = DoSomeThingAsync("Jack");
Task[] MyTasks = new Task[3]{ task1, task2, task3 };
await Task.WhenAll(MyTasks);
Console.WriteLine("All tasks have completed.");
}
控制台输出中的结果:
Harry is starting on thread 1
Fred is starting on thread 1
Jack is starting on thread 1
Jack is now on thread 4
Fred is now on thread 5
Harry is now on thread 6
Fred is now on thread 8
Harry is now on thread 5
Jack is now on thread 6
Fred is now on thread 7
Harry is now on thread 6
Jack is now on thread 5
Harry is now on thread 7
Fred is now on thread 5
Jack is now on thread 6
Harry is now on thread 5
Jack is now on thread 6
Fred is now on thread 9
All tasks have completed.
你会注意到代码正在执行的实际线程会跳来跳去,在我的系统上,我看到了六个不同的线程——你的里程会有所不同。
但重要的是,第一个<code>控制台。WriteLine()始终在主线程上运行,即线程一。
在控制台应用程序中,您不需要使用任务。Run()让CPU密集型任务在不同的线程池上运行。简单地等待一个任务,
await Task.Yield();
我试图构建一个实现Runnable的任务对象,该对象通过begin()方法生成一个新线程,将其自身用作线程中的Runnable对象? 然后... 这可能吗?或者抽象的可运行类在新线程中使用自己会有问题吗?
我有两个JS函数。一个叫另一个。在调用函数中,我想调用另一个函数,等待该函数完成,然后继续。例如,伪代码: 我想出了这个解决方案,但不知道这是否是一个明智的方法。 这合法吗?有没有更优雅的处理方法?也许用jQuery?
目前,我使用的是firebase实时数据库。因此,我的数据更改来自另一个线程。因此,我无法控制何时更新新的数据。然后我如何知道何时调用以刷新UI? 谢谢
我如何启动两个线程,其中thread1首先执行,thread2在thread1结束时启动,而主方法线程可以在不锁定其他两个线程的情况下继续工作? 我尝试了join(),但是它需要从线程调用,线程必须等待另一个线程,没有办法执行类似thread2.join(thread1)的操作;因此,如果我在main()中调用join,我将有效地停止主线程的执行,而不仅仅是Thread2的执行。 #编辑:为什么我
我试过这样的事情: create(new observable.onsubscribe>(){@override public void call(subscriber>subscriber){subscriber.onnext(getList());subscriber.oncompleted();}}).subscribe... 但是这个订阅在一个迭代上,onNext只传递完整的列表,而不是列
问题内容: 我使用的是Spring 4,我注意到了一个奇怪的行为……如果我从普通实例方法多次调用异步方法,那么它们都将在不同的线程中调用,并在随机时间完成。但是,如果我多次从另一个异步方法中调用一个异步方法,那么它们将按顺序完成。我有这样的事情: 我正在使用默认的异步执行器。我应该换一个吗?但是,该执行程序不会重用任何线程,而是每次都启动另一个线程,因此应该没问题……这仅仅是巧合吗?但是我尝试了十