.net多线程

一、多线程编程方式

常见传统的多线程编程方式new Thread、 ThreadPool.QueueUserWorkItem、 APM模式Begin**,End**,.net提供了很多IO和网络的这类方法。略过..

刚用System.Threading.Timer(call back, state, duetime,period)写了个游戏的小功能。虚拟庄家X先生,每分钟Points必须有增长,否则自动+5

    public static class Xman
    {
        public static int Points { get { return _points; } }

        /// <summary>
        /// 初始Xman points
        /// </summary>
        private static int _points = ParticipateRepository.Instance.GetXmanPoints();

        private static int preMin_points = Points;

        public static int Win(int points)
        {       
            return Interlocked.Add(ref _points, points);
        }

        /// <summary>
        /// 如果Xman的point没增长,每分钟加5point
        /// </summary>
        private static System.Threading.Timer timer = new Timer((state) => 
        {
            if (preMin_points < Points)
            {
                preMin_points = Points;
            }
            else
            {
                ParticipateRepository.Instance.IncreXmanPoints(Win(5));               
            }
        },null,60000, 60000);
    }
View Code 

 

.net 4.0开始推荐使用Task,TaskScheduler调度,对于非LongRunning的task都是放到ThreadPool队列的

public virtual async Task<bool> LogParticipate(string prizeName)
        {                         
            Task<bool> t =  Task.Run(() =>
            {
                Dictionary<string, string> dicPara = new Dictionary<string, string>();
                dicPara.Add("prizeName", prizeName);
                return MailHelper.Send(_cicid, "Ten Years-Lucky Roulette", dicPara,
                    Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "EmailTemplate"), "Roulette.html");
            });
            return await t;  
        }
View Code

可在t.Wait(),t.Result处捕捉AggregateException,Task间顺序执行ContinueWith, 取消一个task的执行是用CancellationToken

对于创建多个相同的task,建议使用Parallel.Foreach...

二、线程同步

并行要考虑临界资源、执行顺序,最常见的同步方式lock(Monitor.Enter&&Monitor.Exit), Let's see在哪些场景下优先使用的其他方式

1) Interlocked 提供对整数的+,-,compare,exchange原子操作,像Xman的分数处理 

2) Mutex,可实现跨域,例如,单应用实例

3) ReaderWriterLock, 用于共享reader的场景

4) MethodImpl和SynchronizationAttribute,使用繁琐,不如直接lock

5) AutoResetEvent、ManualResetEvent,线程之间传递事件,简单通过Set发信号,WaitOne等待信号来控制代码是否往下执行。Auto区别于Manual的是set一次只会有一个线程WaitOne收到信号,此时IsRelease为false。

6) 线程安全的集合Concurrent*,用来作为临界集合资源的数据结构,very nice。例如,轮盘游戏在用户中奖后,优惠券编码等不能相同

/// <summary>
/// key:prize name; value:usable prize
/// </summary>
private static Dictionary<string, ConcurrentQueue<PrizeDefined>> dicPrizeStore = new Dictionary<string, ConcurrentQueue<PrizeDefined>>();

PrizeDefined p = null;
if (dicPrizeStore.ContainsKey(prize.Name))
{
    if (!string.IsNullOrEmpty(prize.SKU))
    {
         dicPrizeStore[prize.Name].TryPeek(out p);
     }
     else
     {   //有唯一标识的奖品
          dicPrizeStore[prize.Name].TryDequeue(out p);
      }                                  
}
View Code

也很适用于相同资源只收取一个的场景,如后台防止多次提交

private static ConcurrentDictionary<long, DateTime> dic = new ConcurrentDictionary<long, DateTime>();
//防止http多次请求
    if (!dic.TryAdd(DxUserToken.Instance.CICID, DateTime.Now))
    {
         return false;
     }
     try
     {}
     catch{}
     finally
     {
          DateTime d;
          dic.TryRemove(DxUserToken.Instance.CICID, out d);
      }
View Code

 

三、Try Avoid Sync

锁会降低程序并发性,设计时尽量避免同步。如Xman只有一个Points属性,DB中直接作为user Participate表的一个列,用户玩一次,insert一条。而Xman自增线程update固定的一条非用户记录。这样避免了锁的存在。

posted @ 2015-09-10 16:42  zzq417  阅读(259)  评论(4编辑  收藏  举报