C\#유일한 검사 요청

필드 설명 사용:
네트워크 요청 에서 보 내 는 요청 이 자주 발생 합 니 다.서버 응답 은 성공 적 이지 만 돌아 올 때 네트워크 고장 이 발생 하여 클 라 이언 트 가 요청 결 과 를 받 지 못 하면 클 라 이언 트 프로그램 은 네트워크 고장 으로 판단 하고 같은 요청 을 반복 적 으로 보 낼 수 있 습 니 다.물론 인터페이스 에서 요청 결과 조회 인 터 페 이 스 를 정의 한다 면 이런 중복 은 상대 적 으로 적 을 것 이다.특히 거래 류 의 데 이 터 는 중복 전송 요청 을 피해 야 한다.또 다른 상황 은 사용자 가 인터페이스 단 추 를 너무 빨리 클릭 하여 똑 같은 내용 의 요청 이 발생 하면 백 엔 드 도 여과 해 야 한 다 는 것 이다.이런 것 은 보통 시스템 도 킹 에 나타 나 제3자 시스템 의 업무 논 리 를 제어 할 수 없고 자신의 업무 논리 에서 한정 해 야 한다.
기타 필요 설명:
이러한 요 구 는 일반적으로 시간 범위 와 높 은 병발 의 특징 이 존재 하 는데 짧 은 시간 안에 중복 되 는 요구 가 발생 하기 때문에 모듈 에 대해 높 은 병발 성 을 지원 해 야 한다.
기술 실현:
요청 한 업무 내용 에 대해 MD5 요약 을 하고 MD5 요약 을 캐 시 에 저장 하 며 모든 요청 데 이 터 는 이 공공 호출 방법 을 통 해 판단 합 니 다.
코드 구현:
공공 호출 코드 유 니 크 체크 는 단일 모드 로 유일한 대상 을 만 들 고 다 중 스 레 드 호출 시 하나의 통 일 된 캐 시 라 이브 러 리 만 방문 할 수 있 습 니 다.

/*
   * volatile        const  ,volatile        (type specifier)。
   *                       。
   *     volatile,           :           ,              。
   */
  private static readonly object lockHelper = new object();
 
  private volatile static UniqueCheck _instance;  
 
  /// <summary>
  ///       
  /// </summary>
  /// <returns></returns>
  public static UniqueCheck GetInstance()
  {
   if (_instance == null)
   {
    lock (lockHelper)
    {
     if (_instance == null)
      _instance = new UniqueCheck();
    }
   }
   return _instance;
  }
volatile 의 수정자 에 주의해 야 합 니 다.실제 테스트 과정 에서 이 수정자 가 없 으 면 높 은 병발 상황 에서 오류 가 발생 할 수 있 습 니 다.
동시 처리 대기 열 을 사용자 정의 합 니 다.코드 는 다음 과 같 습 니 다:ConcurrentLinkedQueue

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace PackgeUniqueCheck
{
 /// <summary>
 ///        ,  100      
 /// </summary>
 /// <typeparam name="T"></typeparam>
 public class ConcurrentLinkedQueue<T>
 {
  private class Node<K>
  {
   internal K Item;
   internal Node<K> Next;

   public Node(K item, Node<K> next)
   {
    this.Item = item;
    this.Next = next;
   }
  }

  private Node<T> _head;
  private Node<T> _tail;

  public ConcurrentLinkedQueue()
  {
   _head = new Node<T>(default(T), null);
   _tail = _head;
  }

  public bool IsEmpty
  {
   get { return (_head.Next == null); }
  }
  /// <summary>
  ///     
  /// </summary>
  /// <param name="item"></param>
  public void Enqueue(T item)
  {
   Node<T> newNode = new Node<T>(item, null);
   while (true)
   {
    Node<T> curTail = _tail;
    Node<T> residue = curTail.Next;

    //  _tail     process  
    if (curTail == _tail)
    {
     //A    process  C  ,_tail        
     if (residue == null)
     {
      //C   process   tail  ,     tail  
      if (Interlocked.CompareExchange<Node<T>>(
       ref curTail.Next, newNode, residue) == residue)
      {
       //D     tail
       Interlocked.CompareExchange<Node<T>>(ref _tail, newNode, curTail);
       return;
      }
     }
     else
     {
      //B         D  
      Interlocked.CompareExchange<Node<T>>(ref _tail, residue, curTail);
     }
    }
   }
  }
  /// <summary>
  ///      
  /// </summary>
  /// <param name="result"></param>
  /// <returns></returns>
  public bool TryDequeue(out T result)
  {
   Node<T> curHead;
   Node<T> curTail;
   Node<T> next;
   while (true)
   {
    curHead = _head;
    curTail = _tail;
    next = curHead.Next;
    if (curHead == _head)
    {
     if (next == null) //Queue  
     {
      result = default(T);
      return false;
     }
     if (curHead == curTail) //Queue  Enqueue   node    
     {
      //      Process    
      Interlocked.CompareExchange<Node<T>>(ref _tail, next, curTail);
     }
     else
     {
      // next.Item    CAS  
      result = next.Item;
      //  _head      ,  _head  next   
      if (Interlocked.CompareExchange<Node<T>>(ref _head,
       next, curHead) == curHead)
       break;
     }
    }
   }
   return true;
  }
  /// <summary>
  ///           
  /// </summary>
  /// <param name="result"></param>
  /// <returns></returns>
  public bool TryGetTail(out T result)
  {
   result = default(T);
   if (_tail == null)
   {
    return false;
   }
   result = _tail.Item;
   return true;
  }
 }
}
매우 간단 한 유일한 검사 논리 이지 만 효율 적 이 고 병행 지원 이 높 으 며 신뢰성 이 높 으 며 메모리 사용량 이 적 으 려 면 이러한 수 요 를 실현 하고 세밀 한 시 뮬 레이 션 테스트 를 해 야 한다.

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Collections;

namespace PackgeUniqueCheck
{
 public class UniqueCheck
 {
  /*
   * volatile        const  ,volatile        (type specifier)。
   *                       。
   *     volatile,           :           ,              。
   */
  private static readonly object lockHelper = new object();

  private volatile static UniqueCheck _instance;  

  /// <summary>
  ///       
  /// </summary>
  /// <returns></returns>
  public static UniqueCheck GetInstance()
  {
   if (_instance == null)
   {
    lock (lockHelper)
    {
     if (_instance == null)
      _instance = new UniqueCheck();
    }
   }
   return _instance;
  }

  private UniqueCheck()
  {
   //            ,      
   _DataKey = Hashtable.Synchronized(new Hashtable());
   Queue myqueue = new Queue();
   _DataQueue = Queue.Synchronized(myqueue);
   _Myqueue = new ConcurrentLinkedQueue<string>();
   _Timer = new Thread(DoTicket);
   _Timer.Start();
  }

  #region       
  /// <summary>
  ///              :   1  
  ///     :1-7200000,  1   2  
  /// </summary>
  /// <param name="value"></param>
  public void SetTimeSpan(int value)
  {
   if (value > 0&& value <=7200000)
   {
    _TimeSpan = value;
   }
  }
  /// <summary>
  ///     Cache        
  ///    :1-5000000,1 500 
  /// </summary>
  /// <param name="value"></param>
  public void SetCacheMaxNum(int value)
  {
   if (value > 0 && value <= 5000000)
   {
    _CacheMaxNum = value;
   }
  }
  /// <summary>
  ///              
  /// </summary>
  /// <param name="value"></param>
  public void SetIsShowMsg(bool value)
  {
   Helper.IsShowMsg = value;
  }
  /// <summary>
  ///         
  ///    :1-CacheMaxNum,           10%-20%
  /// </summary>
  /// <param name="value"></param>
  public void SetBlockNumExt(int value)
  {
   if (value > 0 && value <= _CacheMaxNum)
   {
    _BlockNumExt = value;
   }
  }
  /// <summary>
  ///       
  ///    :1-max,              
  ///       ,          ,           
  /// </summary>
  /// <param name="value"></param>
  public void SetBlockSpanTime(int value)
  {
   if (value > 0)
   {
    _BlockSpanTime = value;
   }
  }
  #endregion

  #region     
  /// <summary>
  ///       
  /// </summary>
  private Thread _runner = null;
  /// <summary>
  ///          
  /// </summary>
  private ConcurrentLinkedQueue<string> _Myqueue = null;
  /// <summary>
  ///           
  /// </summary>
  private Hashtable _DataKey = null;
  /// <summary>
  ///       
  /// </summary>
  private Queue _DataQueue = null;
  /// <summary>
  ///            :   1  
  /// </summary>
  private int _TimeSpan = 3000;
  /// <summary>
  ///        
  /// </summary>
  private Thread _Timer = null;
  /// <summary>
  ///   Cache        
  /// </summary>
  private int _CacheMaxNum = 500000;
  /// <summary>
  ///         
  /// </summary>
  private int _BlockNumExt = 10000;
  /// <summary>
  ///       
  /// </summary>
  private int _BlockSpanTime = 100;
  #endregion

  #region     
  private void StartRun()
  {
   _runner = new Thread(DoAction);
   _runner.Start();
   Helper.ShowMsg("        !");
  }

  private string GetItem()
  {
   string tp = string.Empty;
   bool result = _Myqueue.TryDequeue(out tp);
   return tp;
  }
  /// <summary>
  ///       
  /// </summary>
  private void DoAction()
  {
   while (true)
   {
    while (!_Myqueue.IsEmpty)
    {
     string item = GetItem();
     _DataQueue.Enqueue(item);
     if (!_DataKey.ContainsKey(item))
     {
      _DataKey.Add(item, DateTime.Now);
     }
    }
    //Helper.ShowMsg("        ,          ...");
    Thread.Sleep(2);
   }
  }
  /// <summary>
  ///         
  /// </summary>
  private void DoTicket()
  {
   while (true)
   {
    Helper.ShowMsg("        :" + _DataQueue.Count.ToString());
    if (_DataQueue.Count > _CacheMaxNum)
    {
     while (true)
     {
      Helper.ShowMsg(string.Format("     :{0},        :{1},        ...", _DataQueue.Count, _CacheMaxNum.ToString()));
      string item = _DataQueue.Dequeue().ToString();
      if (!string.IsNullOrEmpty(item))
      {
       if (_DataKey.ContainsKey(item))
       {
        _DataKey.Remove(item);
       }
       if (_DataQueue.Count <= _CacheMaxNum)
       {
        Helper.ShowMsg("    ,        ...");
        break;
       }
      }
     }
    }
    Thread.Sleep(_TimeSpan);
   }
  }

  /// <summary>
  ///         
  ///                     
  ///           
  /// </summary>
  private void BlockThread()
  {
   if (_DataQueue.Count > _CacheMaxNum + _BlockNumExt)
   {
    Thread.Sleep(_BlockSpanTime);
   }
  }
  #endregion

  #region     
  /// <summary>
  ///       
  /// </summary>
  public void Start()
  {
   if (_runner == null)
   {
    StartRun();
   }
   else
   {
    if (_runner.IsAlive == false)
    {
     StartRun();
    }
   }

  }
  /// <summary>
  ///       
  /// </summary>
  public void Stop()
  {
   if (_runner != null)
   {
    _runner.Abort();
    _runner = null;
   }
  }

  /// <summary>
  ///       
  /// </summary>
  /// <param name="item">    </param>
  /// <returns>true:        ,      ,false:       ,      </returns>
  public bool AddItem(string item)
  {
   BlockThread();
   item = Helper.MakeMd5(item);
   if (_DataKey.ContainsKey(item))
   {
    return false;
   }
   else
   {
    _Myqueue.Enqueue(item);
    return true;
   }
  }
  /// <summary>
  ///             
  /// </summary>
  /// <param name="item">    </param>
  /// <returns>true:          ,false:         </returns>
  public bool CheckItem(string item)
  {
   item = Helper.MakeMd5(item);
   return _DataKey.ContainsKey(item);
  }
  #endregion 

 }
}
아 날로 그 테스트 코드:

private static string _example = Guid.NewGuid().ToString();

  private static UniqueCheck _uck = null;

  static void Main(string[] args)
  {
   _uck = UniqueCheck.GetInstance();
   _uck.Start();
   _uck.SetIsShowMsg(false);
   _uck.SetCacheMaxNum(20000000);
   _uck.SetBlockNumExt(1000000);
   _uck.SetTimeSpan(6000);

   _uck.AddItem(_example);
   Thread[] threads = new Thread[20];

   for (int i = 0; i < 20; i++)
   {
    threads[i] = new Thread(AddInfo);
    threads[i].Start();
   }

   Thread checkthread = new Thread(CheckInfo);
   checkthread.Start();

   string value = Console.ReadLine();

   checkthread.Abort();
   for (int i = 0; i < 50; i++)
   {
    threads[i].Abort();
   }
   _uck.Stop();
  }

  static void AddInfo()
  {
   while (true)
   {
    _uck.AddItem(Guid.NewGuid().ToString());
   }
  }

  static void CheckInfo()
  {
   while (true)
   {
    Console.WriteLine("    :{0}...", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"));
    Console.WriteLine("    :{0}", _uck.AddItem(_example));
    Console.WriteLine("    :{0}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"));
          //        ,          
    //Thread.Sleep(1000);
   }
   
  }
테스트 캡 처:

총결산
이상 은 이 글 의 모든 내용 입 니 다.본 고의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가 치 를 가지 기 를 바 랍 니 다.여러분 의 저희 에 대한 지지 에 감 사 드 립 니 다.

좋은 웹페이지 즐겨찾기