使用ThreadPool发起同步的调用
让我们来思考一下这个问题它的本质是如果你采用异步调用则无法同时发起多个请求对同一个proxy而言。那么如果是同步调用的话就自然没有这个问题了吧。但是如果同步调用的话却又会阻塞线程导致你根本无法发起第二个请求。这有何难呢我们大不了可以开两个线程然后让这两个线程同时工作在它们上面运行各自的同步调用方法不就可以了么为了让大家更好地理解我用最简单的做法来实现吧ThreadPool是一个静态类顾名思义它代表了线程池的概念。对于初学者而言创建和控制线程并非易事。所以.NET提供了这个ThreadPool实际上相当于是傻瓜式的多线程多任务的接口。span stylecolor:#000000span stylebackground-color:#ffffffspan stylecolor:#0000ffusing/span System; span stylecolor:#0000ffusing/span System.Windows.Forms; span stylecolor:#0000ffusing/span System.Threading; span stylecolor:#0000ffnamespace/span WindowsFormsApplication1 { span stylecolor:#0000ffpublic/span span stylecolor:#0000ffpartial/span span stylecolor:#0000ffclass/span Form1 : Form { span stylecolor:#0000ffpublic/span Form1() { InitializeComponent(); } localhost.WebService1 proxy span stylecolor:#0000ffnew/span localhost.WebService1(); span stylecolor:#0000ffprivate/span span stylecolor:#0000ffvoid/span button1_Click(span stylecolor:#0000ffobject/span sender, EventArgs e) { ThreadPool.QueueUserWorkItem( (obj) { var result proxy.HelloWorld(); MessageBox.Show(result); }); } span stylecolor:#0000ffprivate/span span stylecolor:#0000ffvoid/span button2_Click(span stylecolor:#0000ffobject/span sender, EventArgs e) { ThreadPool.QueueUserWorkItem( (obj) { var result proxy.HelloWorld(); MessageBox.Show(result); }); } } } /span/spanThreadPool类型有一个静态方法QueueUserWorkItem顾名思义就是将用户任务排进队列等待执行。你可能会说那么这是要排队么当然但是既然称为Pool也即是池就自然不止一个线程它里面有好多个线程可以使用自然就可以同时运行多个任务了。关于这一点大家可以类比一下我们在超市买完东西之后去收银台付费的情况。很多大超市都有声势浩大的一排收银台【注意】要实现多线程还有很多做法例如下面这样无疑也是可以的span stylecolor:#000000span stylebackground-color:#ffffffspan stylecolor:#0000ffusing/span System; span stylecolor:#0000ffusing/span System.Windows.Forms; span stylecolor:#0000ffusing/span System.Threading; span stylecolor:#0000ffnamespace/span WindowsFormsApplication1 { span stylecolor:#0000ffpublic/span span stylecolor:#0000ffpartial/span span stylecolor:#0000ffclass/span Form1 : Form { span stylecolor:#0000ffpublic/span Form1() { InitializeComponent(); } localhost.WebService1 proxy span stylecolor:#0000ffnew/span localhost.WebService1(); span stylecolor:#0000ffprivate/span span stylecolor:#0000ffvoid/span button1_Click(span stylecolor:#0000ffobject/span sender, EventArgs e) { (span stylecolor:#0000ffnew/span Thread((obj) { var result proxy.HelloWorld(); MessageBox.Show(result); })).Start(); } span stylecolor:#0000ffprivate/span span stylecolor:#0000ffvoid/span button2_Click(span stylecolor:#0000ffobject/span sender, EventArgs e) { (span stylecolor:#0000ffnew/span Thread((obj) { var result proxy.HelloWorld(); MessageBox.Show(result); })).Start(); } } } /span/span这个做法是由我们自己创建并启动了一个线程。这看起来虽然比较刺激但并见得是多么好的一个做法。尤其是你对线程操作并不是特别熟悉的情况下我推荐你还是多用ThreadPool至于其他的做法如Backgroundworker以及自定义Callback等这里就不列举了。4. 线程安全问题这样做看起来是解决了问题了。但是大家要知道通常情况下我们希望调用Web Service获得的结果能进一步地进行处理或者要显示在界面上。例如下面这样span stylecolor:#000000span stylebackground-color:#ffffffspan stylecolor:#0000ffusing/span System; span stylecolor:#0000ffusing/span System.Windows.Forms; span stylecolor:#0000ffusing/span System.Threading; span stylecolor:#0000ffnamespace/span WindowsFormsApplication1 { span stylecolor:#0000ffpublic/span span stylecolor:#0000ffpartial/span span stylecolor:#0000ffclass/span Form1 : Form { span stylecolor:#0000ffpublic/span Form1() { InitializeComponent(); } localhost.WebService1 proxy span stylecolor:#0000ffnew/span localhost.WebService1(); span stylecolor:#0000ffprivate/span span stylecolor:#0000ffvoid/span button1_Click(span stylecolor:#0000ffobject/span sender, EventArgs e) { ThreadPool.QueueUserWorkItem( (obj) { var result proxy.HelloWorld(); strongspan stylecolor:#0000ffthis/span.Text result;span stylecolor:#008000//将结果显示在窗体的标题上/span/strong }); } span stylecolor:#0000ffprivate/span span stylecolor:#0000ffvoid/span button2_Click(span stylecolor:#0000ffobject/span sender, EventArgs e) { ThreadPool.QueueUserWorkItem( (obj) { var result proxy.HelloWorld(); strongspan stylecolor:#ff0000span stylecolor:#0000ffthis/span.Text result;/span/strong }); } } } /span/span再次运行这个代码就会发现它又报错了这回报告的错误是下面这样的这个错误的意思是说当前的线程需要访问控件”Form1”但是Form1并不是它所创建的。什么是当前线程就是我们用ThreadPool发起的一个任务所占用的线程。而Form1这个控件是谁创建的呢是主线程创建的。这就是我们常说的线程安全性问题也就是说在多个不同的线程之间是不能互相访问到一些资源的。还是用超市的收银做例子如果我是排在1号收银台那么2号收银员是不可以把我的钱拿走的。那么如何解决这个问题呢其实这还是比较简单的Windows Forms(或者WPF)都内置了一些机制来解决span stylecolor:#000000span stylebackground-color:#ffffffspan stylecolor:#0000ffusing/span System; span stylecolor:#0000ffusing/span System.Windows.Forms; span stylecolor:#0000ffusing/span System.Threading;/span/span