VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > Python基础教程 >
  • C#线程 入门(4)

  

在生产应用程序中的所有线程进入方法上都需要一个异常处理程序,就像在主线程上一样(通常在执行堆栈中处于更高级别)。未处理的异常会导致整个应用程序关闭。与一个丑陋的对话!

在编写此类异常处理块时,很少会忽略该错误:通常,您会记录异常的详细信息,然后显示一个对话框,允许用户自动将这些详细信息提交到您的Web服务器。然后,您可能会关闭该应用程序-因为该错误有可能破坏了程序的状态。但是,这样做的代价是用户将丢失其最近的工作-例如打开的文档。

WPF和Windows Forms应用程序的“全局”异常处理事件(Application.DispatcherUnhandledException和Application.ThreadException)仅针对在主UI线程上引发的异常触发。您仍然必须手动处理工作线程上的异常。

 AppDomain.CurrentDomain.UnhandledException在任何未处理的异常上触发,但没有提供防止应用程序随后关闭的方法。但是,在某些情况下,您不需要处理工作线程上的异常,因为.NET Framework会为您处理异常。这些将在接下来的部分中介绍,分别是:

 

线程池

每当启动线程时,都会花费数百微秒来组织诸如新鲜的私有局部变量堆栈之类的事情。每个线程(默认情况下)也消耗大约1 MB的内存。线程池通过共享和回收线程来减少这些开销,从而允许在非常细粒度的级别上应用多线程,而不会影响性能。当利用多核处理器以“分而治之”的方式并行执行计算密集型代码时,这很有用。

线程池还限制了将同时运行的工作线程总数。过多的活动线程限制了操作系统的管理负担,并使CPU缓存无效。一旦达到限制,作业将排队并仅在另一个作业完成时才开始。这使任意并发的应用程序(例如Web服务器)成为可能。 (异步方法模式是一种高级技术,通过高效利用池化线程来进一步实现这一点;我们在C#4.0的第23章“ Nutshell”中对此进行了描述)。

有多种进入线程池的方法:

  1. 通过任务并行库(来自Framework 4.0)
  2. 通过调用ThreadPool.QueueUserWorkItem
  3. 通过异步委托
  4. 通过BackgroundWorker

以下构造间接使用线程池:

任务并行库(TPL)和PLINQ具有足够的功能和高级功能,即使在线程池不重要的情况下,您也希望使用它们来协助多线程。我们将在第5部分中详细讨论这些内容。现在,我们将简要介绍如何使用Task类作为在池线程上运行委托的简单方法。

使用池线程时需要注意以下几点:

 

您可以通过Thread.CurrentThread.IsThreadPoolThread属性查询当前是否在池化线程上执行。

通过TPL进入线程池

您可以使用“任务并行库”中的“任务”类轻松地输入线程池。 Task类是在Framework 4.0中引入的:如果您熟悉较早的构造,请考虑将非通用Task类替换为ThreadPool.QueueUserWorkItem,而将通用Task <TResult>替换为异步委托。与旧版本相比,新版本的结构更快,更方便且更灵活。

 

要使用非泛型Task类,请调用Task.Factory.StartNew,并传入目标方法的委托:

1
2
3
4
5
6
7
8
9
static void Main()    // The Task class is in System.Threading.Tasks
{
  Task.Factory.StartNew (Go);
}
 
static void Go()
{
  Console.WriteLine ("Hello from the thread pool!");
}

  

Task.Factory.StartNew返回一个Task对象,您可以使用该对象来监视任务-例如,您可以通过调用其Wait方法来等待它完成。

 

调用任务的Wait方法时,所有未处理的异常都可以方便地重新抛出到主机线程中。 (如果您不调用Wait而是放弃任务,则未处理的异常将像普通线程一样关闭进程。)

 

通用Task <TResult>类是非通用Task的子类。它使您可以在完成执行后从任务中获取返回值。在下面的示例中,我们使用Task <TResult>下载网页:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static void Main()
{
  // Start the task executing:
  Task<string> task = Task.Factory.StartNew<string>
    ( () => DownloadString ("http://www.linqpad.net") );
 
  // We can do other work here and it will execute in parallel:
  RunSomeOtherMethod();
 
  // When we need the task's return value, we query its Result property:
  // If it's still executing, the current thread will now block (wait)
  // until the task finishes:
  string result = task.Result;
}
 
static string DownloadString (string uri)
{
  using (var wc = new System.Net.WebClient())
    return wc.DownloadString (uri);
}

相关教程