Task.Yield会导致强制捕获上下文,虽然会在另一个线程执行,但在UI线程中可能无法抢占上下文导致死锁大石头 编写于 2019-07-10 15:21:23
diff --git a/NewLife.Core/Collections/ICluster.cs b/NewLife.Core/Collections/ICluster.cs
index b0fae7a..dc18d0e 100644
--- a/NewLife.Core/Collections/ICluster.cs
+++ b/NewLife.Core/Collections/ICluster.cs
@@ -66,7 +66,7 @@ namespace NewLife.Collections
try
{
item = cluster.Get();
- return await func(item);
+ return await func(item).ConfigureAwait(false);
}
finally
{
diff --git a/NewLife.Core/Http/TinyHttpClient.cs b/NewLife.Core/Http/TinyHttpClient.cs
index 6bbca13..88119e7 100644
--- a/NewLife.Core/Http/TinyHttpClient.cs
+++ b/NewLife.Core/Http/TinyHttpClient.cs
@@ -87,7 +87,7 @@ namespace NewLife.Http
#if NET4
tc.Connect(remote.Address, remote.Port);
#else
- await tc.ConnectAsync(remote.Address, remote.Port);
+ await tc.ConnectAsync(remote.Address, remote.Port).ConfigureAwait(false);
#endif
Client = tc;
@@ -95,7 +95,7 @@ namespace NewLife.Http
}
// 发送
- if (request != null) await request.CopyToAsync(ns);
+ if (request != null) await request.CopyToAsync(ns).ConfigureAwait(false);
// 接收
var buf = new Byte[64 * 1024];
@@ -104,7 +104,7 @@ namespace NewLife.Http
#else
var source = new CancellationTokenSource(Timeout);
- var count = await ns.ReadAsync(buf, 0, buf.Length, source.Token);
+ var count = await ns.ReadAsync(buf, 0, buf.Length, source.Token).ConfigureAwait(false);
#endif
return new Packet(buf, 0, count);
@@ -124,7 +124,7 @@ namespace NewLife.Http
StatusCode = -1;
// 发出请求
- var rs = await SendDataAsync(uri, req);
+ var rs = await SendDataAsync(uri, req).ConfigureAwait(false);
if (rs == null || rs.Count == 0) return null;
// 解析响应
@@ -133,7 +133,7 @@ namespace NewLife.Http
// 头部和主体分两个包回来
if (rs != null && rs.Count == 0 && ContentLength != 0)
{
- rs = await SendDataAsync(null, null);
+ rs = await SendDataAsync(null, null).ConfigureAwait(false);
}
// chunk编码
@@ -357,7 +357,7 @@ namespace NewLife.Http
var client = pool.Get();
try
{
- return (await client.SendAsync(uri, null))?.ToStr();
+ return (await client.SendAsync(uri, null).ConfigureAwait(false))?.ToStr();
}
finally
{
diff --git a/NewLife.Core/Remoting/ApiClient.cs b/NewLife.Core/Remoting/ApiClient.cs
index f93fa4d..afe5010 100644
--- a/NewLife.Core/Remoting/ApiClient.cs
+++ b/NewLife.Core/Remoting/ApiClient.cs
@@ -172,8 +172,9 @@ namespace NewLife.Remoting
public virtual async Task<Object> InvokeAsync(Type resultType, String action, Object args = null, Byte flag = 0)
{
// 让上层异步到这直接返回,后续代码在另一个线程执行
+ //!!! Task.Yield会导致强制捕获上下文,虽然会在另一个线程执行,但在UI线程中可能无法抢占上下文导致死锁
#if !NET4
- await Task.Yield();
+ //await Task.Yield();
#endif
Open();
@@ -182,16 +183,16 @@ namespace NewLife.Remoting
try
{
- return await ApiHostHelper.InvokeAsync(this, this, resultType, act, args, flag);
+ return await ApiHostHelper.InvokeAsync(this, this, resultType, act, args, flag).ConfigureAwait(false);
}
catch (ApiException ex)
{
// 重新登录后再次调用
if (ex.Code == 401)
{
- await Cluster.InvokeAsync(client => OnLoginAsync(client, true));
+ await Cluster.InvokeAsync(client => OnLoginAsync(client, true)).ConfigureAwait(false);
- return await ApiHostHelper.InvokeAsync(this, this, resultType, act, args, flag);
+ return await ApiHostHelper.InvokeAsync(this, this, resultType, act, args, flag).ConfigureAwait(false);
}
throw;
@@ -212,7 +213,7 @@ namespace NewLife.Remoting
public virtual async Task<TResult> InvokeAsync<TResult>(String action, Object args = null, Byte flag = 0)
{
// 发送失败时,返回空
- var rs = await InvokeAsync(typeof(TResult), action, args, flag);
+ var rs = await InvokeAsync(typeof(TResult), action, args, flag).ConfigureAwait(false);
if (rs == null) return default;
return (TResult)rs;
@@ -226,7 +227,7 @@ namespace NewLife.Remoting
public virtual TResult Invoke<TResult>(String action, Object args = null, Byte flag = 0)
{
// 发送失败时,返回空
- var rs = InvokeAsync(typeof(TResult), action, args, flag).Result;
+ var rs = TaskEx.Run(() => InvokeAsync(typeof(TResult), action, args, flag)).Result;
if (rs == null) return default;
return (TResult)rs;
@@ -258,7 +259,7 @@ namespace NewLife.Remoting
{
var act = action;
- return (TResult)await ApiHostHelper.InvokeAsync(this, client, typeof(TResult), act, args, flag);
+ return (TResult)await ApiHostHelper.InvokeAsync(this, client, typeof(TResult), act, args, flag).ConfigureAwait(false);
}
Task<IMessage> IApiSession.SendAsync(IMessage msg) => Cluster.InvokeAsync(client => client.SendMessageAsync(msg)).ContinueWith(t => t.Result as IMessage);
@@ -286,10 +287,10 @@ namespace NewLife.Remoting
public virtual async Task<Object> LoginAsync()
{
#if !NET4
- await Task.Yield();
+ //await Task.Yield();
#endif
- return await Cluster.InvokeAsync(client => OnLoginAsync(client, false));
+ return await Cluster.InvokeAsync(client => OnLoginAsync(client, false)).ConfigureAwait(false);
}
#endregion
diff --git a/NewLife.Core/Remoting/ApiNetServer.cs b/NewLife.Core/Remoting/ApiNetServer.cs
index effb24b..fa7b601 100644
--- a/NewLife.Core/Remoting/ApiNetServer.cs
+++ b/NewLife.Core/Remoting/ApiNetServer.cs
@@ -96,9 +96,9 @@ namespace NewLife.Remoting
/// <param name="args">参数</param>
/// <param name="flag">标识</param>
/// <returns></returns>
- public async Task<TResult> InvokeAsync<TResult>(String action, Object args = null, Byte flag = 0) => (TResult)await ApiHostHelper.InvokeAsync(_Host, this, typeof(TResult), action, args, flag);
+ public async Task<TResult> InvokeAsync<TResult>(String action, Object args = null, Byte flag = 0) => (TResult)await ApiHostHelper.InvokeAsync(_Host, this, typeof(TResult), action, args, flag).ConfigureAwait(false);
- async Task<IMessage> IApiSession.SendAsync(IMessage msg) => await Session.SendMessageAsync(msg) as IMessage;
+ async Task<IMessage> IApiSession.SendAsync(IMessage msg) => await Session.SendMessageAsync(msg).ConfigureAwait(false) as IMessage;
Boolean IApiSession.Send(IMessage msg) => Session.SendMessage(msg);
}
diff --git a/NewLife.Core/Remoting/IApiHost.cs b/NewLife.Core/Remoting/IApiHost.cs
index 7a3cd36..721b338 100644
--- a/NewLife.Core/Remoting/IApiHost.cs
+++ b/NewLife.Core/Remoting/IApiHost.cs
@@ -80,9 +80,9 @@ namespace NewLife.Remoting
try
{
if (session is IApiSession ss)
- rs = await ss.SendAsync(msg);
+ rs = await ss.SendAsync(msg).ConfigureAwait(false);
else if (session is ISocketRemote client)
- rs = (await client.SendMessageAsync(msg)) as IMessage;
+ rs = (await client.SendMessageAsync(msg).ConfigureAwait(false)) as IMessage;
else
throw new InvalidOperationException();
diff --git a/NewLife.Core/Yun/Map.cs b/NewLife.Core/Yun/Map.cs
index bb9fe5b..989c370 100644
--- a/NewLife.Core/Yun/Map.cs
+++ b/NewLife.Core/Yun/Map.cs
@@ -131,7 +131,7 @@ namespace NewLife.Yun
LastString = null;
LastKey = key;
- var rs = await _Client.DownloadStringAsync(url);
+ var rs = await _Client.DownloadStringAsync(url).ConfigureAwait(false);
//// 删除无效密钥
//if (IsValidKey(rs)) RemoveKey(key);
@@ -147,7 +147,7 @@ namespace NewLife.Yun
{
LastResult = null;
- var html = await GetStringAsync(url);
+ var html = await GetStringAsync(url).ConfigureAwait(false);
if (html.IsNullOrEmpty()) return default(T);
var rs = new JsonParser(html).Decode();
diff --git a/XCode/Service/DbClient.cs b/XCode/Service/DbClient.cs
index 7b80329..d0086ef 100644
--- a/XCode/Service/DbClient.cs
+++ b/XCode/Service/DbClient.cs
@@ -67,7 +67,7 @@ namespace XCode.Service
var cookie = Rand.NextString(16);
var pass2 = cookie.GetBytes().RC4(Password.GetBytes()).ToBase64();
- var rs = await InvokeWithClientAsync<LoginInfo>(client, "Db/Login", new { Db, UserName, pass = pass2, cookie });
+ var rs = await InvokeWithClientAsync<LoginInfo>(client, "Db/Login", new { Db, UserName, pass = pass2, cookie }).ConfigureAwait(false);
if (Setting.Current.Debug) XTrace.WriteLine("登录{0}成功!{1}", Servers.FirstOrDefault(), rs.ToJson());
return Info = rs;
@@ -103,7 +103,7 @@ namespace XCode.Service
{
var arg = Encode(sql, ps);
- var rs = await InvokeAsync<Packet>("Db/Query", arg);
+ var rs = await InvokeAsync<Packet>("Db/Query", arg).ConfigureAwait(false);
//if (rs == null || rs.Total == 0) return null;
var ds = new DbTable();
@@ -120,7 +120,7 @@ namespace XCode.Service
{
//var arg = Encode(tableName, null);
- return await InvokeAsync<Int64>("Db/QueryCount", new { tableName });
+ return await InvokeAsync<Int64>("Db/QueryCount", new { tableName }).ConfigureAwait(false);
}
/// <summary>异步执行</summary>
@@ -131,7 +131,7 @@ namespace XCode.Service
{
var arg = Encode(sql, ps);
- return await InvokeAsync<Int64>("Db/Execute", arg);
+ return await InvokeAsync<Int64>("Db/Execute", arg).ConfigureAwait(false);
}
#endregion