线程

黑客

成员
加入
2017年9月12日
消息
11
编程经验
5-10
我正在阅读很多关于C#中的线程和异步处理,我已经晕了。显然存在 很多种方法 这样做,我不知道有什么区别。
到目前为止,我得到了(更明显)

  1. 旧的线程类
  2. 与beginInvoke和EndInvoke的异步调用
  3. 异步 - 等待方式

有人可以解释一下差异是什么(也有一些作者认为#3实际上没有创建一个不同的线程)

更重要的是,我试图了解我所获得的一些提前代码,它使用异步处理和回调很多,所以一个准时的问题:

如何知道在哪个操作运行的线程? (我读到某处,但我找不到它 :( 这样做的方法。关于线程的东西。一些方法?我想,但我不确定)
 

jmplhinney.

C#论坛主持人
工作人员
加入
2011年4月23日
消息
3,732
地点
悉尼,澳大利亚
编程经验
10+
Microsoft随着时间的推移,Microsoft将不同的多线程功能添加到.NET Framework及其相关语言。最初,如果您想执行一些背景工作或使用ThreadPool类,通常会直接创建一个线程对象,如果您想队列多个后台任务,则可以使用ThreadPool类。 BeginInvoke / EndInvoke基本上用于构建异步API,即,您可以创建封装异步功能的类型,并且消费者可以相当容易地使用,而无需执行太多的工作。稍后,他们介绍了与更简单的接口提供更多功能的任务并行库,现在异步/等待是一种使用TPL的更简单方法。

简而言之,除非您有特定的原因,否则您应该在您自己的代码中使用异步/等待。否则最常见的原因是您正在使用本身不使用异步/等待的现有异步API。请注意,Microsoft已添加异步API的异步/等待版本到已经使用不同机制实现了异步API的许多类。

简单来说,异步方法将返回一个任务对象,基本上是在后台执行的方法。它可能会或可能不会在不同的线程上执行,但这取决于TPL。您不需要在线程方面进行思考,而是仅仅是前景和背景。当您调用异步方法时,您可以等待它。如果您没有,该方法将立即返回,您可以返回任务。您的代码将继续在前台执行,并且该任务中的方法将继续在后台完成。在完成后,您将无法使用后台方法的结果,此时您可以从任务中获取其结果。

如果您调用异步方法时,您可能无法等待的一个例子是如果您有多个独立的后台任务以执行。如果您要单独等待每个人,那么他们将被串行执行,每次都在开始之前完成前一个完成。相反,您可以串行启动它们,而不是等待每个人,因此它们都会并行执行。在开始每个人之前,您可以等待它们作为一个组,因此您的代码不会继续,直到您获得所有结果。

如果您调用异步方法并等待它,那么在任务完成之前,您的代码将等待该调用。这有点像一个同步呼叫,但不同的是,而不是阻止其他一切,等待关键字将导致控制跳回前一个来电者,以便它可以继续在该背景工作时继续执行其他前景工作。这确保了确保可以并行完成最大的前景和背景工作。只要您在使用异步检索的任何数据之前都有等待时,您可以确保不会尝试使用仍在检索过程中的数据。

使用所有同步方法查看此代码:
public void Method1()
{
    var data = Method2();

    // work1A
    // work1B
    // work1C

    // Use data here.
}

public object Method2()
{
    var result = Method3();

    // work2A
    // work2B
    // work2C

    return result;
}

public object Method3()
{
    object result;

    // work3A
    // work3B
    // work3C

    return result;
}

如果您要在该代码中调用方法1,则它将调用方法2和块,这意味着在方法2完成之前,甚至不会尝试工作1A,Work1B和Work1c。在方法2中,它将调用方法3并块,直到它完成,这意味着方法3必须在工作2A之前完成,甚至会尝试Work2B和Work2C。这意味着Work3a,Work3b和Work3c必须在工作2a,Work2b和Work2c之前完成,并且他们必须在工作之前完成,工作1b和工作1c将开始。

现在看看使用异步/等待的类似代码:
public async Task Method1()
{
    var dataTask = Method2();

    // work1A
    // work1B
    // work1C

    var data = await dataTask;

    // Use data here.
}

public async Task<object> Method2()
{
    var resultTask = Method3();

    // work2A
    // work2B
    // work2C

    return await resultTask;
}

public async Task<object> Method3()
{
    return await Task.Run(() =>
                          {
                              object result;

                              // work3A
                              // work3B
                              // work3C

                              return result;
                          });
}

在这种情况下,方法1调用方法2并且简单地继续执行Work1A,Work1B和Work1C,而Method2在后台执行。同样,方法2调用方法3并且简单地继续执行Work2a,Work2b和Work2c,而Method3在后台执行。这意味着您可以同时进行三组工作,从而充分利用系统资源,而不是在申请中制作任务等待它们实际上并非实际上所依赖的任务。

在方法1中,代码仅等待执行方法2的任务,即在需要时,即,即在其实际使用方法2返回的数据之前。通过时间方法1到达该点,方法2可能已经完成,因此方法1可以立即继续,因此它根本不会被延迟。如果方法2尚未完成,则方法1将等到它。至少它已经设法在方法中获得了一些其他工作,而不是在方法2完成后仍然必须执行该工作,然后在使用返回的数据之前完成。

同样,方法2只会等待方法3,即必须在它返回之前完成。当它到达那个点时,方法3可能已经完成,因此方法2可以立即返回,但是,如果方法3仍在执行,则至少方法2已经能够在此期间完成一些工作,并且仍然仍然没有那种工作一旦方法3完成。

因此,使用异步/等待时,您应该尽可能迟到等待异步方法。如果您需要立即使用结果,然后等待呼叫,您将直接恢复结果,例如,
var result = await SomeMethodAsync();

// Use result here.

如果您不需要立即使用结果,那么不要等待呼叫并获得任务后,然后在使用稍后使用结果之前等待任务,例如,
var resultTask = SomeMethodAsync();

// Do some more work here.

var result = await resultTask;

// Use result here.
 

jmplhinney.

C#论坛主持人
工作人员
加入
2011年4月23日
消息
3,732
地点
悉尼,澳大利亚
编程经验
10+
请注意,在上面的第二个代码段中,您使用Task.RUN方法在您不实际调用任何异步方法的异步方法中创建一个任务以等待。
 
最佳 底部