RestSharp组件中止线程问题
Posted BoSet
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RestSharp组件中止线程问题相关的知识,希望对你有一定的参考价值。
背景:下单流程里面,生成发货单是在独立线程池完成的,有些批发订单数据巨大,频繁拆包生成多个发货单
排查:由于ES刷新是在一个独立的api里面,一开始怀疑是异步线程频繁请求api导致中断的
- SemaphoreSlim:对同时访问资源或资源池的线程数加以限制,结果:无效
- lock:顺序执行,使线程等待,结果:无效
- 日记调试:在api里面打上日记,发现中止线程的时候根本没有进入api,现在基本可以断定是调用端的问题
查看调用端代码
// 改造前
//var client = new RestClient($"ElasticsearchBaseApi/api/Elasticsearch/UpdateElasticsearchOrder");
//var resp = client.Execute(request);
// 改造后(使用单例/静态变量)
var resp = client.Execute(request);
发现该项目好多地方都习惯是直接new一个RestClient来使用,正常业务量不大的时候是没问题的,如果业务量大了这里就会导致线程数过高最终导致线程中止
延伸:静态变量与单例
静态变量:众所周知静态变量只会初始化一次,声明时开辟内存空间知道程序结束,所有单例共享该空间
单例:所有实例指针地址都是同一个,是同一块内存空间
测试:
如果遇到这种错误,解决方法:鼠标移动到错误信息让编译工具自动解决,实际上是在csproj文件添加 AllowUnsafeBlocks为true
using System;
namespace ERP.JK.Util
class Student
private static Student _Instance;
public static Student Instance
get
if (_Instance==null)
_Instance = new Student();
return _Instance;
public int Age;
class Program
private static Student student = new Student();
private static Student student2 = new Student();
static void Main(string[] args)
try
Student s1 = Student.Instance;
s1.Age = 10;
unsafe
fixed (int* p = &s1.Age)
Console.WriteLine("Address:0x0:x,value:1", (int)p,s1.Age);
Student s2 = Student.Instance;
s1.Age = 20;
unsafe
fixed (int* p = &s2.Age)
Console.WriteLine("Address:0x0:x,value:1", (int)p, s2.Age);
student.Age = 30;
unsafe
fixed (int* p = &student.Age)
Console.WriteLine("Address:0x0:x,value:1", (int)p, student.Age);
student2.Age = 40;
unsafe
fixed (int* p = &student2.Age)
Console.WriteLine("Address:0x0:x,value:1", (int)p, student2.Age);
catch (Exception ex)
throw ex;
运行结果:
- 可以看出s1,s2里面的Aage地址都是一样的
- student 与student2 因为分别实例并且存储在静态变量中,所以地址不一样
.NET 中的线程中止
【中文标题】.NET 中的线程中止【英文标题】:Thread Abort in .NET 【发布时间】:2010-02-01 20:57:23 【问题描述】:我有一个线程正在分析文件并对数据库进行事务调用,每个事务都有一个审计条目作为其事务的一部分。调用 Thread.Abort() 来停止文件的处理有什么大问题吗?而不是到处散布丑陋的安全点?
文件将在 Abort 调用后关闭。
【问题讨论】:
【参考方案1】:明显的问题是放弃事务的风险,这可能会导致阻塞一段不确定的时间(或直到超时)。但是你可以让所有分类变得一团糟——不可恢复的Monitor
锁、信号量等、内存泄漏等。
简而言之:尽量避免中止线程,除非您确切地知道它当时正在做什么。你可以知道它在做什么的唯一方法是它是否已经在一个已知的“安全点”(用你的术语)——所以你不妨抛出一个异常或其他东西,让它以一种有管理的方式自我提升.
【讨论】:
事务正在运行的会话将被关闭,线程正在运行的类将被释放。这意味着服务器将回滚事务,并且可以从取消功能正确关闭该类。哪些锁、信号量等会丢失? @Will:执行清理时可能会发生中止。这可能意味着您的清理不会完成。此外,Abort 可能会破坏 lock 语句(有一些保护措施,但不能保证不会)。所以你最终可能会得到一个不会再次解锁的锁。 @Ruben:线程中止不会中断清理逻辑:“如果您在受限执行区域 (CER)、finally 块、catch 块、.cctor 内执行,我们不会处理线程中止, “乔·达菲。 @Sergey:不幸的是,这些并不是唯一可以进行清理的地方。例如,lock(x)
看起来像 Monitor.Enter(x) try ... finally Monitor.Exit(x);
,这意味着在 Enter 和 try 之间可能会发生 Abort。此外,不能保证清理代码在 finally 等内部,它也可以是不期望抛出异常的代码(因为它似乎是异常安全的,如果忽略异步异常,或者它是设置代码设置清理代码要使用的标志)。中止使所有这些事情变得非常复杂。
@Ruben:我完全同意,处理异步异常非常危险且容易出错。【参考方案2】:
最佳实践:仅在您终止进程时中止线程。
【讨论】:
【参考方案3】:尝试 Thread.Interrupt() 强制线程退出等待状态。
MSDN page
【讨论】:
以上是关于RestSharp组件中止线程问题的主要内容,如果未能解决你的问题,请参考以下文章
android组件化开发,12个View绘制流程高频面试题,实战解析
android组件化开发,12个View绘制流程高频面试题,实战解析
带有 RestSharp 的 Paypal Rest Api 在 xamarin android 中不起作用