C#线程(异步委托)
<h2>delegate匿名方法(匿名函数)</h2><p>1. 函数和方法等价。匿名方法能够让你声明一个方法体而不需要给它指定一个名字,它们以一个“普通的”方法存在,但是在你的代码中没有任何方法显式调用它。,返回参数不需要声明,会根据[语句块]决定。</p>
<p>2. 匿名方法只能在使用委托的时候创建,它们通过delegate关键字创建或者Lambda表达式(匿名函数)。定义方式:<span style="color: rgba(0, 0, 255, 1)"><code class="csharp keyword">delegate</code></span><code class="csharp plain">(</code><code class="csharp plain">显式参数,显式参数) {语句块}</code></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)"> delegate</span>(<span style="color: rgba(0, 0, 255, 1)">bool</span> x) { <span style="color: rgba(0, 0, 255, 1)">return</span> x ? <span style="color: rgba(128, 0, 128, 1)">1</span> : <span style="color: rgba(128, 0, 128, 1)">2</span>; }</pre>
</div>
<p>3. 匿名函数总是和委托一齐使用 : 定义委托变量=匿名函数</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(51, 204, 204, 1)"> Func</span><<span style="color: rgba(0, 0, 255, 1)">bool</span>, <span style="color: rgba(0, 0, 255, 1)">int</span>> fun = <span style="color: rgba(0, 0, 255, 1)">delegate</span>(<span style="color: rgba(0, 0, 255, 1)">bool</span> x) { <span style="color: rgba(0, 0, 255, 1)">return</span> x ? <span style="color: rgba(128, 0, 128, 1)">1</span> : <span style="color: rgba(128, 0, 128, 1)">2</span>; };</pre>
</div>
<p> </p>
<h2>Lambda表达式(匿名函数)</h2>
<p>1. "Lambda表达式"可以是一个表达式也可以是一个匿名函数,Lambda表达式都使用Lambda运算符“<span style="color: rgba(0, 0, 0, 1)"><strong>=></strong></span>”。Lambda运算符的左边是[输入参数(如果有)],右边是[表达式]或[语句块],返回参数不需要声明,会根据[表达式]或[语句块]决定。表达式只能有一条语句,语句块可以有多条语句。</p>
<p class="alt">(参数1,参数2)=<span class="tag">>表达式或语句块 </span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(128, 0, 128, 1)">1</span>. () => { <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 128, 1)">1</span>; }; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">无参数 =>语句块 </span>
<span style="color: rgba(128, 0, 128, 1)">2</span>. ( x) => x * <span style="color: rgba(128, 0, 128, 1)">5</span>; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">单参数,隐式类型 =>表达式 </span>
<span style="color: rgba(128, 0, 128, 1)">3</span>. ( x) => { <span style="color: rgba(0, 0, 255, 1)">return</span> x * <span style="color: rgba(128, 0, 128, 1)">5</span>; }; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">单参数,隐式类型=>语句块 </span>
<span style="color: rgba(128, 0, 128, 1)">4</span>. (<span style="color: rgba(0, 0, 255, 1)">int</span> x) => x * <span style="color: rgba(128, 0, 128, 1)">5</span>; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">单参数,显式类型=>表达式 </span>
<span style="color: rgba(128, 0, 128, 1)">5</span>. (<span style="color: rgba(0, 0, 255, 1)">int</span> x) => { <span style="color: rgba(0, 0, 255, 1)">return</span> x * <span style="color: rgba(128, 0, 128, 1)">5</span>; }; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">单参数,显式类型=>语句块 </span>
<span style="color: rgba(128, 0, 128, 1)">6</span>. ( x, y) => x * y ; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">多参数,隐式类型=> 表达式</span></pre>
</div>
<p> 2. Lambda表达式可以和委托一齐使用 : 定义委托变量=Lambda表达式</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(51, 204, 204, 1)"> Func</span><<span style="color: rgba(0, 0, 255, 1)">bool</span>, <span style="color: rgba(0, 0, 255, 1)">int</span>> fun = (<span style="color: rgba(0, 0, 255, 1)">bool</span> x) => { <span style="color: rgba(0, 0, 255, 1)">return</span> x ? <span style="color: rgba(128, 0, 128, 1)">1</span> : <span style="color: rgba(128, 0, 128, 1)">2</span>; };</pre>
</div>
<p> </p>
<h2>delegate委托</h2>
<p>1. 委托的用途就是把方法当作参数来进行传递。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">delegate</span> <span style="color: rgba(0, 0, 255, 1)">int</span> MethodtDelegate(<span style="color: rgba(0, 0, 255, 1)">int</span> x, <span style="color: rgba(0, 0, 255, 1)">int</span> y);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义委托</span>
MethodtDelegate md = (x, y) => { <span style="color: rgba(0, 0, 255, 1)">return</span> x * y; };<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义委托变量</span>
md(<span style="color: rgba(128, 0, 128, 1)">1</span>, <span style="color: rgba(128, 0, 128, 1)">2</span>);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">调用委托</span></pre>
</div>
<p>2. 可以用<span style="color: rgba(255, 0, 255, 1)"><strong>+=</strong></span>对一个委托变量绑定多个方法。这叫多播委托,利用<span style="color: rgba(255, 0, 255, 1)"><strong> -=</strong></span>移除方法。</p>
<div class="cnblogs_code">
<pre>md += (x, y) => { <span style="color: rgba(0, 0, 255, 1)">return</span> x +<span style="color: rgba(0, 0, 0, 1)"> y; };
md </span>+= (x, y) => { <span style="color: rgba(0, 0, 255, 1)">return</span> x - y;};</pre>
</div>
<p>3. C#预定义的三种泛型委托<span style="color: rgba(51, 204, 204, 1)">Action</span><>、<span style="color: rgba(51, 204, 204, 1)">Func</span><>、<span style="color: rgba(51, 204, 204, 1)">Predicate</span><></p>
<p>3.1. <span style="color: rgba(51, 204, 204, 1)">Action</span><> 至少0个参数,至多16个参数,无返回值。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(51, 204, 204, 1)">Action</span><<span style="color: rgba(0, 0, 255, 1)">int</span>,<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">float</span>> action=<span style="color: rgba(51, 102, 255, 1)">null</span>;</pre>
</div>
<p>3.2.<span style="color: rgba(0, 255, 255, 1)"> <span style="color: rgba(51, 204, 204, 1)">Func</span></span><> 至少1个参数(返回值参数),至多16个参数,有返回值。最后一个参数为返回值参数</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(51, 204, 204, 1)">Func</span><<span style="color: rgba(0, 0, 255, 1)">int</span>,<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">float</span>> func=<span style="color: rgba(0, 0, 255, 1)">null</span>;</pre>
</div>
<p>3.3. <span style="color: rgba(51, 204, 204, 1)">Predicate</span><> 只有一个参数,默认返回bool。</p>
<p>Predicate一般用于Lambda表达式里面的条件,表示定义一组条件并确定指定对象是否符合这些条件的方法,此方法常在集合的查找中被用到。如:数组,正则拼配的结果集中被用到。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(51, 204, 204, 1)">Predicate</span><<span style="color: rgba(0, 0, 255, 1)">int</span>> predicate=<span style="color: rgba(0, 0, 255, 1)">null</span>;</pre>
</div>
<p> </p>
<h3>0 异步委托介绍:</h3>
<table border="1">
<tbody>
<tr>
<td><span style="color: rgba(255, 0, 255, 1)">Invoke</span></td>
<td>开始同步调用委托(同步调用Invoke,无论是否新开线程都会导致阻塞Invoke所在的线程)</td>
</tr>
<tr>
<td style="width: 100px"><span style="color: rgba(255, 0, 255, 1)">BeginInvoke</span></td>
<td>开始异步调用委托</td>
</tr>
<tr>
<td style="width: 100px"><span style="color: rgba(255, 0, 255, 1)">EndInvoke</span></td>
<td>返回异步调用的结果集(当使用BeginInvoke异步调用方法时,如果方法未执行完,EndInvoke方法就会一直阻塞,直到被调用的方法执行完毕)</td>
</tr>
<tr>
<td style="width: 100px"><span style="color: rgba(255, 0, 255, 1)">AsyncCallback</span></td>
<td>结束异步调用后要执行的操作。</td>
</tr>
</tbody>
</table>
<p>1. (Control的Invoke和BeginInvoke)是在Control线程上调用。所以如果在<span style="color: rgba(51, 204, 204, 1)">Control</span>线程上调用<span style="color: rgba(51, 204, 204, 1)">Control</span>的Invoke或BeginInvoke来进行调用某个委托方法来达到跨线程或异步是错误的。那<span style="color: rgba(51, 204, 204, 1)">Control</span>的Invoke和BeginInvoke的用途是什么呢,他的用途是让其他线程的某个方法在Control所在线程上执行。如果在其他线程上调用<span style="color: rgba(51, 204, 204, 1)">Control</span>的Invoke,这时候其他线程会被阻塞,直到<span style="color: rgba(51, 204, 204, 1)">Control</span>线程执行完其他线程才会在继续执行。而<span style="color: rgba(51, 204, 204, 1)">Control</span>的BeginInvoke不会让其他线程阻塞。</p>
<p>2. (Delegate的Invoke和BeginInvoke)是在线程池中调用。 所以一般如果某个方法执行时间特别长,都会用<span style="color: rgba(51, 204, 204, 1)">Delegate</span>的BeginInvoke执行,这样<span style="color: rgba(51, 204, 204, 1)">Control</span>线程就不会被阻塞。但要注意,如果在<span style="color: rgba(51, 204, 204, 1)">Control</span>线程中调用<span style="color: rgba(51, 204, 204, 1)">Delegate</span>的Invoke,虽然<span style="color: rgba(51, 204, 204, 1)">Delegate</span>的Invoke是从线程池的线程同步调用,但他还是会阻塞<span style="color: rgba(51, 204, 204, 1)">Control</span>线程的,所以要用<span style="color: rgba(51, 204, 204, 1)">Delegate</span>的BeginInvoke才能实现异步。还有一种情况就是在线程池上用<span style="color: rgba(51, 204, 204, 1)">Delegate</span>的Invoke会导致线程池上<span style="color: rgba(51, 204, 204, 1)">Delegate</span>所在线程被阻塞,直到<span style="color: rgba(51, 204, 204, 1)">Control</span>所在线程上执行完线程池上<span style="color: rgba(51, 204, 204, 1)">Delegate</span>所在线程才能继续执行。</p>
<p>3. 使用BeginInvoke时特别要注意的就是BeginInvoke里面所用到的变量必须全部使用参数形式传进去,防止异步时被幕改变量值。</p>
<h3>1 异步有阻塞:</h3>
<p>例如有一个程序现在要分别调用 接口1和接口2,并要获取到他们两个接口的结果集后才能继续执行后面的代码。接口1调用耗时为10秒,接口2调用耗时5秒,如果是同步调用这两个接口并要处理这两个接口返回值时,一共需要耗时15秒。但如果我们使用异步同时调用这两个接口,那我们一般最多只需要10秒就可以返回两个接口的结果集。但是由于我们要在调用接口的这个方法退出前必须要获取到接口返回的结果,所以我们要用EndInvoke;这时候调用线程会处于阻塞状态。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义调用接口1委托</span>
<span style="color: rgba(51, 204, 204, 1)">Func<</span><span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">string</span>> getInfo1 = (<span style="color: rgba(0, 0, 255, 1)">string</span> txt) => { <span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">调用接口1</span><span style="color: rgba(0, 128, 0, 1)">*/ </span>Thread.Sleep(<span style="color: rgba(128, 0, 128, 1)">10000</span>); <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">1</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">; };
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义调用接口2委托</span>
<span style="color: rgba(51, 204, 204, 1)">Func</span><<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">string</span>> getInfo2 = (<span style="color: rgba(0, 0, 255, 1)">string</span> txt) => { <span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">调用接口2</span><span style="color: rgba(0, 128, 0, 1)">*/ </span>Thread.Sleep(<span style="color: rgba(128, 0, 128, 1)">5000</span>); <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">2</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">; };
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">开始调用接口1</span>
<span style="color: rgba(51, 204, 204, 1)">IAsyncResult</span> ar1 = getInfo1.BeginInvoke(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">调用接口1</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(0, 0, 255, 1)">null</span>, <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">开始调用接口2</span>
<span style="color: rgba(51, 204, 204, 1)">IAsyncResult</span> ar2 = getInfo2.BeginInvoke(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">调用接口2</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(0, 0, 255, 1)">null</span>, <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">string</span> result1 = getInfo1.EndInvoke(ar1);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">处理接口1返回结果</span>
<span style="color: rgba(0, 0, 255, 1)">string</span> result2 = getInfo2.EndInvoke(ar2);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">处理接口2返回结果</span>
<span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = <span style="color: rgba(128, 0, 128, 1)">0</span>; i < <span style="color: rgba(128, 0, 128, 1)">10</span>; i++<span style="color: rgba(0, 0, 0, 1)">)
{
}</span></pre>
</div>
<p> </p>
<h3>2 异步有阻塞加超时:</h3>
<p>利用WaitOne方法,这个方法的超时设置指代码运行但这句代码时开始计算时间,所以同时有多个BeginInvoke异步调用时要注意。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义调用接口1委托</span>
<span style="color: rgba(51, 204, 204, 1)">Func</span><<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">string</span>> getInfo1 = (<span style="color: rgba(0, 0, 255, 1)">string</span> txt) => { <span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">调用接口1</span><span style="color: rgba(0, 128, 0, 1)">*/</span> Thread.Sleep(<span style="color: rgba(128, 0, 128, 1)">1000</span>); <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">1</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">; };
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义调用接口2委托</span>
<span style="color: rgba(51, 204, 204, 1)">Func</span><<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">string</span>> getInfo2 = (<span style="color: rgba(0, 0, 255, 1)">string</span> txt) => { <span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">调用接口2</span><span style="color: rgba(0, 128, 0, 1)">*/</span> Thread.Sleep(<span style="color: rgba(128, 0, 128, 1)">7000</span>); <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">2</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">; };
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">开始调用接口1</span>
<span style="color: rgba(51, 204, 204, 1)">IAsyncResult</span> ar1 = getInfo1.BeginInvoke(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">调用接口1</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(0, 0, 255, 1)">null</span>, <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">开始调用接口2</span>
<span style="color: rgba(51, 204, 204, 1)">IAsyncResult</span> ar2 = getInfo2.BeginInvoke(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">调用接口2</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(0, 0, 255, 1)">null</span>, <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">string result1 = getInfo1.EndInvoke(ar1);</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">处理接口1返回结果
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">string result2 = getInfo2.EndInvoke(ar2);</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">处理接口2返回结果</span>
<span style="color: rgba(0, 0, 255, 1)">int</span> TimeOut = <span style="color: rgba(128, 0, 128, 1)">5000</span>;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">超时时间为5秒</span>
<span style="color: rgba(51, 204, 204, 1)">Stopwatch</span> sw = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(51, 204, 204, 1)"> Stopwatch</span>();
sw.Start();
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (ar1.AsyncWaitHandle.WaitOne(TimeOut))
{
getInfo1.EndInvoke(ar1); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方法成功执行返回值</span>
<span style="color: rgba(0, 0, 0, 1)">sw.Stop();
TimeOut </span>-= (<span style="color: rgba(0, 0, 255, 1)">int</span>)sw.ElapsedMilliseconds;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">减掉第一个异步的耗时</span>
<span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
{
sw.Stop();
TimeOut </span>= <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">超时</span>
<span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (ar2.AsyncWaitHandle.WaitOne(TimeOut))
{
getInfo2.EndInvoke(ar2); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方法成功执行返回值</span>
<span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">超时</span>
<span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = <span style="color: rgba(128, 0, 128, 1)">0</span>; i < <span style="color: rgba(128, 0, 128, 1)">10</span>; i++<span style="color: rgba(0, 0, 0, 1)">)
{
}</span></pre>
</div>
<p> </p>
<h3>3 异步无阻塞单向:</h3>
<p>例如异步写日志,<span style="color: rgba(51, 204, 204, 1)">Control</span>线程把要写入的日志信息传递给另外一个线程,不管另外一个线程的执行进度,<span style="color: rgba(51, 204, 204, 1)">Control</span>线程继续执行其他工作。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义写日志委托</span>
<span style="color: rgba(51, 204, 204, 1)">Action</span><<span style="color: rgba(0, 0, 255, 1)">string</span>> writeLog = (<span style="color: rgba(0, 0, 255, 1)">string</span> log) => { <span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">写日志内容</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)"> };
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">在写日志委托回调函数李自动调用EndInvoke</span>
<span style="color: rgba(51, 204, 204, 1)">AsyncCallback</span> callFun = (result) => { ((<span style="color: rgba(51, 204, 204, 1)">Action</span><<span style="color: rgba(0, 0, 255, 1)">string</span>><span style="color: rgba(0, 0, 0, 1)">)result.AsyncState).EndInvoke(result); };
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">开始异步写日志</span>
writeLog.BeginInvoke(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">日志内容</span><span style="color: rgba(128, 0, 0, 1)">"</span>, callFun, writeLog);</pre>
</div>
<p> </p>
<h3>4 异步无阻塞加回调:</h3>
<p>例如有一个UI程序按钮现在要分别调用接口1和接口2,并要获取到他们两个接口的结果集后要更新按钮上的文字。接口1调用耗时为10秒,接口2调用耗时5秒,如果是同步调用这两个接口并要处理这两个接口返回值时,一共需要耗时15秒。UI画面会卡死15秒。但如果我们使用上面1的方法,那UI界面也至少要卡死10秒。所以如果我们把EndInvoke放在一个<span style="color: rgba(51, 204, 204, 1)">AsyncCallback</span>里面处理,当我们按下按钮时,会异步调用这两个接口,由于UI线程没有被阻塞,所以界面不会卡死,当等到接口被调用完成后将会自动调用<span style="color: rgba(51, 204, 204, 1)">AsyncCallback</span>利用EndInvoke返回结果处理按钮上的文字。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span> asynbtn_Click(<span style="color: rgba(0, 0, 255, 1)">object</span><span style="color: rgba(0, 0, 0, 1)"> sender, EventArgs e)
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义调用接口1委托</span>
<span style="color: rgba(51, 204, 204, 1)">Func</span><<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">string</span>> getInterface1 = (<span style="color: rgba(0, 0, 255, 1)">string</span> txt) => { Thread.Sleep(<span style="color: rgba(128, 0, 128, 1)">5000</span>); <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">1</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">; };
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义调用接口2委托</span>
<span style="color: rgba(51, 204, 204, 1)">Func</span><<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">string</span>> getInterface2 = (<span style="color: rgba(0, 0, 255, 1)">string</span> txt) => { Thread.Sleep(<span style="color: rgba(128, 0, 128, 1)">7000</span>); <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">2</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">; };
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">异步全局信息</span>
<span style="color: rgba(51, 204, 204, 1)">AsyncGlobalInfo</span> agi = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(51, 204, 204, 1)"> AsyncGlobalInfo</span>();
agi.gi1 </span>=<span style="color: rgba(0, 0, 0, 1)"> getInterface1;
agi.gi2 </span>=<span style="color: rgba(0, 0, 0, 1)"> getInterface2;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">开始调用接口1</span>
<span style="color: rgba(51, 204, 204, 1)">IAsyncResult</span> ar1 = getInterface1.BeginInvoke(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">调用接口1参数</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(0, 0, 255, 1)">new</span> AsyncCallback((result) => { <span style="color: rgba(51, 204, 204, 1)">AsyncGlobalInfo</span> ic = (<span style="color: rgba(51, 204, 204, 1)">AsyncGlobalInfo</span>)result.AsyncState; ic.result1 = ic.gi1.EndInvoke(result); ic.isCompleted1 = <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">; setText(ic); }), agi);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">开始调用接口2</span>
<span style="color: rgba(51, 204, 204, 1)">IAsyncResult</span> ar2 = getInterface2.BeginInvoke(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">调用接口2参数</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(0, 0, 255, 1)">new</span> AsyncCallback((result) => { <span style="color: rgba(51, 204, 204, 1)">AsyncGlobalInfo</span> ic = (<span style="color: rgba(51, 204, 204, 1)">AsyncGlobalInfo</span>)result.AsyncState; ic.result2 = ic.gi2.EndInvoke(result); ic.isCompleted2 = <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">; setText(ic); }), agi);
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义处理按钮委托</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setText(<span style="color: rgba(51, 204, 204, 1)">AsyncGlobalInfo</span> infoall)
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">判断所有的异步操作都完成</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (infoall.isCompleted1 &&<span style="color: rgba(0, 0, 0, 1)"> infoall.isCompleted2)
{
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.Invoke(<span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(51, 204, 204, 1)">Action</span>(() => { <span style="color: rgba(0, 0, 255, 1)">this</span>.button1.Text = infoall.result1 + <span style="color: rgba(128, 0, 0, 1)">"</span> <span style="color: rgba(128, 0, 0, 1)">"</span> +<span style="color: rgba(0, 0, 0, 1)"> infoall.result2; }));
}
}
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 异步全局信息
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(51, 204, 204, 1)"> AsyncGlobalInfo</span>
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(51, 204, 204, 1)">Func</span><<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">string</span>><span style="color: rgba(0, 0, 0, 1)"> gi1;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">bool</span> isCompleted1 = <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> result1 = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(51, 204, 204, 1)">Func</span><<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">string</span>><span style="color: rgba(0, 0, 0, 1)"> gi2;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">bool</span> isCompleted2 = <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> result2 = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
}</span></pre>
</div>
<p> </p>
<h3>5 异步无阻塞加回调加凭据:</h3>
<p>以上4的方法都有一个问题,那就是耗时问题。1如果这个异步调用必须在指定时间内完成,但4的方法都没有时间限制,所以有可能造成永久等待。2例如一个按钮点击了两次,如果第一次处理时间比第二次长,有可能第二次结果会被第一次覆盖。那要怎么做呢。一般添加一个凭据来验证异步调用和回调是同一次。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">string</span> textBoxToken = <span style="color: rgba(128, 0, 0, 1)">""</span>;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">textBox凭据</span>
<span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span> asynbtn_Click(<span style="color: rgba(0, 0, 255, 1)">object</span><span style="color: rgba(0, 0, 0, 1)"> sender, EventArgs e)
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义调用接口1委托</span>
<span style="color: rgba(51, 204, 204, 1)">Func</span><<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">string</span>> getInterface1 = (<span style="color: rgba(0, 0, 255, 1)">string</span> txt) => { Thread.Sleep(<span style="color: rgba(128, 0, 128, 1)">5000</span>); <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">1</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">; };
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义调用接口2委托</span>
<span style="color: rgba(51, 204, 204, 1)">Func</span><<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">string</span>> getInterface2 = (<span style="color: rgba(0, 0, 255, 1)">string</span> txt) => { Thread.Sleep(<span style="color: rgba(128, 0, 128, 1)">5000</span>); <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">2</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">; };
textBoxToken </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">asynbtn</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">异步全局信息</span>
<span style="color: rgba(51, 204, 204, 1)">AsyncGlobalInfo</span> agi = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(51, 204, 204, 1)"> AsyncGlobalInfo</span>();
agi.gi1 </span>=<span style="color: rgba(0, 0, 0, 1)"> getInterface1;
agi.gi2 </span>=<span style="color: rgba(0, 0, 0, 1)"> getInterface2;
agi.token </span>=<span style="color: rgba(0, 0, 0, 1)"> textBoxToken;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">开始调用接口1</span>
<span style="color: rgba(51, 204, 204, 1)">IAsyncResult</span> ar1 = getInterface1.BeginInvoke(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">调用接口1参数</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(0, 0, 255, 1)">new</span> AsyncCallback((result) => { <span style="color: rgba(51, 204, 204, 1)">AsyncGlobalInfo</span> ic = (<span style="color: rgba(51, 204, 204, 1)">AsyncGlobalInfo</span>)result.AsyncState; ic.result1 = ic.gi1.EndInvoke(result); ic.isCompleted1 = <span style="color: rgba(0, 0, 255, 1)">true</span>; <span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">this</span>.textBoxToken ==<span style="color: rgba(0, 0, 0, 1)"> ic.token) setText(ic); }), agi);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">开始调用接口2</span>
<span style="color: rgba(51, 204, 204, 1)">IAsyncResult</span> ar2 = getInterface2.BeginInvoke(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">调用接口2参数</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(0, 0, 255, 1)">new</span> AsyncCallback((result) => { <span style="color: rgba(51, 204, 204, 1)">AsyncGlobalInfo</span> ic = (<span style="color: rgba(51, 204, 204, 1)">AsyncGlobalInfo</span>)result.AsyncState; ic.result2 = ic.gi2.EndInvoke(result); ic.isCompleted2 = <span style="color: rgba(0, 0, 255, 1)">true</span>; <span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">this</span>.textBoxToken ==<span style="color: rgba(0, 0, 0, 1)"> ic.token) setText(ic); }), agi);
}
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span> copybtn_Click(<span style="color: rgba(0, 0, 255, 1)">object</span><span style="color: rgba(0, 0, 0, 1)"> sender, EventArgs e)
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义调用接口1委托</span>
<span style="color: rgba(51, 204, 204, 1)">Func</span><<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">string</span>> getInterface1 = (<span style="color: rgba(0, 0, 255, 1)">string</span> txt) => { Thread.Sleep(<span style="color: rgba(128, 0, 128, 1)">3000</span>); <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">3</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">; };
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义调用接口2委托</span>
<span style="color: rgba(51, 204, 204, 1)">Func</span><<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">string</span>> getInterface2 = (<span style="color: rgba(0, 0, 255, 1)">string</span> txt) => { Thread.Sleep(<span style="color: rgba(128, 0, 128, 1)">3000</span>); <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">4</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">; };
textBoxToken </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">copybtn</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">异步全局信息</span>
<span style="color: rgba(51, 204, 204, 1)">AsyncGlobalInfo</span> agi = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(51, 204, 204, 1)"> AsyncGlobalInfo</span>();
agi.gi1 </span>=<span style="color: rgba(0, 0, 0, 1)"> getInterface1;
agi.gi2 </span>=<span style="color: rgba(0, 0, 0, 1)"> getInterface2;
agi.token </span>=<span style="color: rgba(0, 0, 0, 1)"> textBoxToken;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">开始调用接口1</span>
<span style="color: rgba(51, 204, 204, 1)">IAsyncResult</span> ar1 = getInterface1.BeginInvoke(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">调用接口1参数</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(0, 0, 255, 1)">new</span> AsyncCallback((result) => { <span style="color: rgba(51, 204, 204, 1)">AsyncGlobalInfo</span> ic = (<span style="color: rgba(51, 204, 204, 1)">AsyncGlobalInfo</span>)result.AsyncState; ic.result1 = ic.gi1.EndInvoke(result); ic.isCompleted1 = <span style="color: rgba(0, 0, 255, 1)">true</span>; <span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">this</span>.textBoxToken ==<span style="color: rgba(0, 0, 0, 1)"> ic.token) setText(ic); }), agi);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">开始调用接口2</span>
<span style="color: rgba(51, 204, 204, 1)">IAsyncResult</span> ar2 = getInterface2.BeginInvoke(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">调用接口2参数</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(0, 0, 255, 1)">new</span> AsyncCallback((result) => { <span style="color: rgba(51, 204, 204, 1)">AsyncGlobalInfo</span> ic = (<span style="color: rgba(51, 204, 204, 1)">AsyncGlobalInfo</span>)result.AsyncState; ic.result2 = ic.gi2.EndInvoke(result); ic.isCompleted2 = <span style="color: rgba(0, 0, 255, 1)">true</span>; <span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">this</span>.textBoxToken ==<span style="color: rgba(0, 0, 0, 1)"> ic.token) setText(ic); }), agi);
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义处理按钮委托</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setText(<span style="color: rgba(51, 204, 204, 1)">AsyncGlobalInfo</span> infoall)
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">判断所有的异步操作都完成</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (infoall.isCompleted1 &&<span style="color: rgba(0, 0, 0, 1)"> infoall.isCompleted2)
{
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.Invoke(<span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(51, 204, 204, 1)">Action</span>(() => { <span style="color: rgba(0, 0, 255, 1)">this</span>.textBox1.Text = infoall.result1 + <span style="color: rgba(128, 0, 0, 1)">"</span> <span style="color: rgba(128, 0, 0, 1)">"</span> +<span style="color: rgba(0, 0, 0, 1)"> infoall.result2; }));
}
}
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 异步全局信息
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(51, 204, 204, 1)"> AsyncGlobalInfo</span>
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> token;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(51, 204, 204, 1)">Func</span><<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">string</span>><span style="color: rgba(0, 0, 0, 1)"> gi1;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">bool</span> isCompleted1 = <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> result1 = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(51, 204, 204, 1)">Func</span><<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">string</span>><span style="color: rgba(0, 0, 0, 1)"> gi2;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">bool</span> isCompleted2 = <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> result2 = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
}</span></pre>
</div>
<p>上面为什么阻塞的用来超时处理,无阻塞用凭据处理呢,你可以理解阻塞的是按代码顺序执行的,无阻塞类似于并发。</p><br><br>
来源:https://www.cnblogs.com/tlmbem/p/10832853.html
頁:
[1]