Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/275.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 正确理解异步/等待。这怎么正确?_C#_Multithreading_Asynchronous_Async Await - Fatal编程技术网

C# 正确理解异步/等待。这怎么正确?

C# 正确理解异步/等待。这怎么正确?,c#,multithreading,asynchronous,async-await,C#,Multithreading,Asynchronous,Async Await,想象一下下面的情况。有一个UI,必须在不阻塞主线程的情况下调用其长时间运行的操作。长时间运行的操作调用intself和其他一些方法,这些方法不与UI线程交互 在大多数情况下,从方法B和C调用的方法与异步方法相比有同步的替代方法。问题是:它们是否可以安全地使用,而不是它们的异步对应物?假设DbContext.DbSet.Add而不是AddAsync // UI public async Task UiMethodAsync() { var result = await MethodAAsy

想象一下下面的情况。有一个UI,必须在不阻塞主线程的情况下调用其长时间运行的操作。长时间运行的操作调用intself和其他一些方法,这些方法不与UI线程交互


在大多数情况下,从方法B和C调用的方法与异步方法相比有同步的替代方法。问题是:它们是否可以安全地使用,而不是它们的异步对应物?假设DbContext.DbSet.Add而不是AddAsync

// UI
public async Task UiMethodAsync()
{
    var result = await MethodAAsync();
}

// some component
public async Task<bool> MethodAAsync()
{
    return await MethodBAsync().ConfigureAwait(false);
}

public async Task<bool> MethodBAsync()
{
    return await MethodCAsync().ConfigureAwait(false);
}

public async Task<bool> MethodCAsync()
{
    return await DbContext.Set<TEntit>.AnyAsync().ConfigureAwait(false);
}
我的问题是:是否有必要使所有方法都异步以防止UI线程阻塞,或者使方法B和C同步如下是否足够好:

// UI
public async Task UiMethodAsync()
{
    var result = await MethodAAsync();
}

// some component
public Task<bool> MethodAAsync()
{
    return Task.FromResult(MethodB());
}

public bool MethodB()
{
    return MethodC();
}

public bool MethodC()
{
    return DbContext.Set<TEntit>.Any();
}
当然,这取决于MethodB和C在做什么,它们是否与ui线程交互。但假设他们没有,只需要计算并返回结果


是否也需要使它们异步?我想不会。我认为这可能避免了管理任务和线程的不必要的开销。

仅仅添加async关键字不足以使代码不阻塞。 返回任务的函数仍将阻塞,除非调用始终是异步的

这很难解释,但要强调代码中的一点:

public async Task<bool> MethodA()
{
    return Task.FromResult(MethodB());
}
相当于

public async Task<bool> MethodA()
{
    bool b = MethodB();
    return Task.FromResult(b);
}

现在很清楚,第一行代码被阻塞,任务直到第二行才被创建。

仅仅添加async关键字不足以使代码不被阻塞。 返回任务的函数仍将阻塞,除非调用始终是异步的

这很难解释,但要强调代码中的一点:

public async Task<bool> MethodA()
{
    return Task.FromResult(MethodB());
}
相当于

public async Task<bool> MethodA()
{
    bool b = MethodB();
    return Task.FromResult(b);
}
现在很清楚,第一行代码正在阻塞,直到第二行才创建任务。

返回任务的方法会创建不会阻塞调用线程的预期。至少在相当长的一段时间内不会。但异步等待机制并不强制执行此操作。编写一个打破这种期望的方法是可能的,而且实际上非常容易。例如:

public Task DoStuffTheWrongWayAsync()
{
    Thread.Sleep(1000); // Simulate a heavy computation, or a blocking call
    return Task.CompletedTask;
}
任何调用此方法的线程都将被阻塞一秒钟,然后将被交给一个已完成的任务。我不知道这个反模式是否有一个已建立的名称。虽然这也可以用于调用方未被阻止,但另一个糟糕的线程被阻止。底线是,一个行为良好的异步方法应该立即返回一个任务,让调用线程自由地执行其他工作,如响应UI事件(如果它是UI线程)。

返回任务的方法会创建一个不会阻止调用线程的期望。至少在相当长的一段时间内不会。但异步等待机制并不强制执行此操作。编写一个打破这种期望的方法是可能的,而且实际上非常容易。例如:

public Task DoStuffTheWrongWayAsync()
{
    Thread.Sleep(1000); // Simulate a heavy computation, or a blocking call
    return Task.CompletedTask;
}

任何调用此方法的线程都将被阻塞一秒钟,然后将被交给一个已完成的任务。我不知道这个反模式是否有一个已建立的名称。虽然这也可以用于调用方未被阻止,但另一个糟糕的线程被阻止。底线是,一个行为良好的异步方法应该立即返回一个任务,让调用线程自由地执行其他工作,如响应UI事件(如果它是UI线程)。

一般来说,如果要使某个对象异步,则从最低级别开始—即实际执行I/O工作的API。在您的示例中,AnyAsync将是异步化的第一件事情。然后允许异步性从这里发展到MethodC,然后是MethodB,然后是MethodA,最后是UiMethod

以异步结束是正常的

是否也需要使它们异步?我想没有

对。如果您希望它们是异步的,那么它们就需要是异步的。Task.FromResult用于同步实现;它们不会是异步的

想象一下下面的情况。有一个用户界面。。。从方法B和C调用的方法具有异步对应方法的同步替代方法。问题是:它们是否可以安全地使用,而不是它们的异步对应物

在UI世界中,可以避免的一件事是在Task.Run中包装对同步方法的调用。例如:


这是一种非常有用的技术,适用于有客户端应用程序、不想阻塞UI、也不想花时间将所有代码转换为异步代码的情况。请注意,这不适用于服务器端应用程序,如ASP.NET。

一般来说,如果要使某些内容异步化,请从最低级别开始,即实际执行I/O工作的API。在您的示例中,AnyAsync将是异步化的第一件事情。然后让异步性通过MethodC,然后MethodB,从这里开始增长, 然后是MethodA,最后是UiMethod

以异步结束是正常的

是否也需要使它们异步?我想没有

对。如果您希望它们是异步的,那么它们就需要是异步的。Task.FromResult用于同步实现;它们不会是异步的

想象一下下面的情况。有一个用户界面。。。从方法B和C调用的方法具有异步对应方法的同步替代方法。问题是:它们是否可以安全地使用,而不是它们的异步对应物

在UI世界中,可以避免的一件事是在Task.Run中包装对同步方法的调用。例如:



这是一种非常有用的技术,适用于有客户端应用程序、不想阻塞UI、也不想花时间将所有代码转换为异步代码的情况。请注意,这不适用于服务器端应用程序,如ASP.NET。

如果MethodC没有等待的内容,则没有理由将其标记为异步。这在很大程度上取决于方法B和C的作用。如果它们执行一些IO,那么最好使它们也异步。如果它们只做CPU密集型的工作,那么您也可以采用第二种方法。在大多数情况下,从方法B和C调用的方法与使用的异步调用相比,有一种同步的替代方法。questino是,如果可以安全地使用它们而不是它们的异步对应项,那么。假设DbContext.DbSet.Add而不是addAsync如果MethodC正在执行需要等待的操作,则每个调用方法都应标记为async,并且每个调用awaited@Theodor佐利亚斯。选择方法名称仅用于演示目的。无论如何,我更新了代码,以避免对其他人进行不好的操作。如果MethodC没有什么可等待的,那么它就没有理由被标记为async。这在很大程度上取决于方法B和C的作用。如果它们执行一些IO,那么最好使它们也异步。如果它们只做CPU密集型的工作,那么您也可以采用第二种方法。在大多数情况下,从方法B和C调用的方法与使用的异步调用相比,有一种同步的替代方法。questino是,如果可以安全地使用它们而不是它们的异步对应项,那么。假设DbContext.DbSet.Add而不是addAsync如果MethodC正在执行需要等待的操作,则每个调用方法都应标记为async,并且每个调用awaited@Theodor佐利亚斯。选择方法名称仅用于演示目的。无论如何,我更新了代码以避免对其他人进行不好的操作。之前很明显,对MethodB的调用将阻止执行线程。但有什么不清楚的:如果使用async await调用MethodAAsync,UI/主线程会被阻塞吗?UI/主线程与执行方法B的线程不同,因此它将被阻塞。B&C都将位于同一UI线程上。使用async/await关键字不足以创建新线程。为什么它会被阻止?为什么您认为它会在不同的线程上?您只能通过Task.Run或DbContext.Set.AnyAsync这样的逻辑切换到不同的线程,为什么AnyAsync要将某些内容放在不同的线程上?它是否调用Task.Run?之前很清楚,对MethodB的调用将阻止正在执行的线程。但有什么不清楚的:如果使用async await调用MethodAAsync,UI/主线程会被阻塞吗?UI/主线程与执行方法B的线程不同,因此它将被阻塞。B&C都将位于同一UI线程上。使用async/await关键字不足以创建新线程。为什么它会被阻止?为什么您认为它会在不同的线程上?您只能通过Task.Run或DbContext.Set.AnyAsync这样的逻辑切换到不同的线程,为什么AnyAsync要将某些内容放在不同的线程上?它是否调用Task.Run?我选择Task.Run来解决不阻塞UI的问题。还有一个问题:如果async/await没有在不同的线程上运行某些东西。那么使用它有什么好处呢?只有当并行性在这两者之间执行其他操作时,才能阻止当前线程?异步是一种不使用线程的并发形式。关键是释放线程。对于客户端应用程序,释放UI线程允许响应。对于服务器应用程序,释放工作线程可以实现可伸缩性。如果asyn/await没有创建新线程,为什么要向任何线程收费?是关于没有额外线程的parallelismn吗?我选择Task.Run来解决不阻塞UI的问题。还有一个问题:如果async/await没有在不同的线程上运行某些东西。那么使用它有什么好处呢?只有当并行性在这两者之间执行其他操作时,才能阻止当前线程?异步是一种不使用线程的并发形式。关键是释放线程。对于客户端应用程序,释放UI线程允许响应。对于服务器应用程序,释放工作线程
允许可伸缩性。如果asyn/await没有创建新线程,为什么它会向任何线程收费?是关于没有额外线程的并行性吗?