.net 异步调用与多线程

.net 异步调用与多线程,.net,asynchronous,windows-services,.net,Asynchronous,Windows Services,我在VB.NET中有一个Windows服务,它按顺序调用几个长时间运行的进程(常规子例程,而不是web svc、远程处理或任何花哨的东西)。我很了解如何实现多线程,因为我们以前从未实现过多线程,这是任务代码。我想改为异步调用例程。我对此很熟悉,并将其作为某些web服务的一部分使用。我错过什么了吗?异步调用似乎是避免多线程问题的一种“穷人”方式。异步调用通常比常规多线程更好,因为它们利用IO完成端口线程,在CPU使用方面效率更高 异步调用似乎是避免多线程问题的“穷人”方式 不一定。Javascri

我在VB.NET中有一个Windows服务,它按顺序调用几个长时间运行的进程(常规子例程,而不是web svc、远程处理或任何花哨的东西)。我很了解如何实现多线程,因为我们以前从未实现过多线程,这是任务代码。我想改为异步调用例程。我对此很熟悉,并将其作为某些web服务的一部分使用。我错过什么了吗?异步调用似乎是避免多线程问题的一种“穷人”方式。

异步调用通常比常规多线程更好,因为它们利用IO完成端口线程,在CPU使用方面效率更高

异步调用似乎是避免多线程问题的“穷人”方式

不一定。Javascript(以及Node.js等Javascript的服务器变体)在单个线程上运行,但使用了大量异步,因此不需要花费太多时间等待长时间运行的操作完成。这是一种优化单个线程的方法,如果你有正确的思维方式,它可以是一种非常强大的编程方法

如果你喜欢异步编程,那就去吧!没有必要仅仅因为任务可以并行化就引入大量线程

然而,如果任务是CPU受限的,那么单个线程将阻塞,异步将不会有明显的帮助。如果任务是IO,那么异步可能是一种方法

编辑:

对不起,我不清楚。我所说的CPU受限是指,如果某个特定操作使用了大量CPU,那么该线程将持续使用,而不会用于其他任务

例如:

// task
long sum = 0;
for (int i = 0; i < 1000000; i++)
    for (int j = 1000000; j > 0; j--)
         sum = i + j;
//任务
长和=0;
对于(int i=0;i<1000000;i++)
对于(int j=1000000;j>0;j--)
总和=i+j;
如果您需要运行上述代码两次,那么使用一个线程的异步模型是没有帮助的,因为一个线程将在整个任务中持续工作。如果有两个线程,则两个线程可以完全同时执行

// task
List<string> urls = GetListOfUrls();
List<string> html = new List<string>();
foreach (var url in urls) 
{
    GetUrlAsync(url, callback: (data) => html.Add(data) );
}
//任务
列表URL=getListoForls();
List html=新列表();
foreach(url中的变量url)
{
GetUrlAsync(url,回调:(数据)=>html.Add(数据));
}
上述任务是一个IO任务。该方法中的大部分时间将用于等待HTTP请求,而不是使用CPU。如果此任务是同步的,则单个线程将具有与第一个线程相同的症状。如果它是异步的,在等待HTTP请求完成时,线程可以做更多的工作,比如启动URL的另一次下载


因此,如果您的任务将花费大量时间等待外部进程,请使用异步。如果任务将消耗cpu,请使用多线程。

我不知道通过异步调用可以避免什么多线程问题。异步调用是多线程的。唯一真正的区别是,异步调用通常用于相对较短的任务,而传统的多线程处理(显式创建线程并启动它运行)通常用于长时间运行的任务

无论如何,您仍然存在相同的并发问题

您可以对长时间运行的任务使用异步调用。事实上,
Task
类有一个构造函数,允许您指定,包括
TaskCreationOptions.LongRunning


使用
Thread
类管理您自己的线程比使用
Task
ThreadPool.QueueUserWorkItem
之类的工具稍微复杂一点,但它也给了您更多的控制。无论采用何种方式,都必须处理并发性问题,如竞争条件和线程安全数据结构(如果多个线程正在修改数据结构)。我不会把异步调用称为“可怜的人的多线程处理”,区别并没有那么大。它们只是完成同一件事情的两种不同方式。

您能解释一下CPU受限和“任务就是IO”这两个短语的含义吗?我知道IO是什么,但上下文是什么?我的例程中唯一的IO是进行常规的CRUDSQL调用。这就是你的意思吗?哇,你刚刚了解了我很多!我真的很感激你花了这么多时间在这个伟大的解释上。很有意义。试着看这里:不管怎样,不要介意细节,但是当方法有一个begininvoke并且需要异步调用它时,这是一种方法。只有在进行异步I/O时,这才是正确的,唯一“更有效”的方法是线程可以对I/O执行等待,从而让其他线程拥有CPU。一般来说,异步调用的效率并不比我们通常认为的多线程处理效率高或低。@Jim Mischel DB connection最终不是要处理套接字上的I/O吗?@Felice:是的。这并没有改变我上面说的任何事情,是吗?@Jim Doesen在使用套接字时,使用异步mehod调用在效率方面没有表现得更好吗?从这个意义上讲,异步调用是多线程的“第一类”方式,不是吗?异步并不一定意味着多线程。Javascript就是一个很好的例子。为C#5开发的新异步特性也是如此。异步可以使用多个线程,但不需要它们。单线程异步代码不需要防止争用条件(使用锁)。@Josh:已授予。但是OP所谈论的异步调用类型确实涉及多线程。我并不完全相信这一点,因为OP没有给出代码或暗示他打算如何做这项工作。但你也可能100%正确。我认为仍然需要注意的是,一些异步任务可以在没有另一个线程旋转的情况下完成。干杯