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组件中止线程问题的主要内容,如果未能解决你的问题,请参考以下文章

C# 中止线程:此平台不支持线程中止

android组件化开发,12个View绘制流程高频面试题,实战解析

android组件化开发,12个View绘制流程高频面试题,实战解析

带有 RestSharp 的 Paypal Rest Api 在 xamarin android 中不起作用

如何中止使用 ThreadPool.QueueUserWorkItem 创建的线程

完成后我应该如何处理线程?离开它还是中止它?