由一個投票算法引發的思考


博主的APP最近又新加了一個小功能,每個員工都可以上傳自己的工作照,其他員工可以點贊,規則是:每張工作照每個員工(除上傳者外)每日可點贊一次。舉個例子:

現有注冊員工ABCD四人,A上傳工作照兩張P1和P2,BCD三人每天可為P1、P2分別點贊一次

博主略加思考,寫了下面一段代碼來實現:

 1         /// <summary>
 2         /// 投票
 3         /// </summary>
 4         /// <param name="id">被投票對象ID</param>
 5         /// <param name="up">贊OR踩</param>
 6         /// <param name="voterName">投票人</param>
 7         /// <param name="canVote">是否允許投票</param>
 8         /// <returns></returns>
 9         public int Vote(int id, bool up, string voterName, out bool canVote)
10         {
11             canVote = repo.RecordVote(voterName, id, timeService.Now);
12             if (canVote)
13             {
14                 return repo.UpdateVoteCount(id, up ? 1 : -1);
19             }
20             return 0;
21         }

注:

1.RecordVote()方法記錄投票信息,UpdateVoteCount()方法執行投票,並返回當前被點贊數

2.再來看看RecordVote()方法的實現:

 1         private static object voteLocker = new Object();
 2 
 3         public bool RecordVote(string voterName, int staffId, DateTime voteTime)
 4         {
 5             lock (voteLocker)
 6             {
 7                 for (; ; )
 8                 {
 9                     var voter = db.Voters.FirstOrDefault(t => t.VoterName == voterName && t.StaffId == staffId);
10                     if (voter != null)
11                     {
12                         if (voter.VoteTime.Date == voteTime.Date)
13                         {
14                             return false;
15                         }
16                         voter.VoteTime = voteTime;
17                     }
18                     else
19                     {
20                         voter = new FVoter() { VoterName = voterName, StaffId = staffId, VoteTime = voteTime };
21                         db.Voters.Add(voter);
22                     }
23                     try
24                     {
25                         db.SaveChanges();
26                         return true;
27                     }
28                     catch (Exception)
29                     {
30                     }
31                 }
32             }
33         }

3.OK,再看看UpdateVoteCount()方法實現

 1         private static object locker = new Object();
 2 
 3         public int UpdateVoteCount(int staffId, int voteCountChange)
 4         {
 5             lock (locker)
 6             {
 7                 for (; ; )
 8                 {
 9                     var staff = db.Staffs.FirstOrDefault(i => i.Id == staffId);
10                     staff.VoteCount += voteCountChange;
12                     try
13                     {
14                         db.SaveChanges();
15                         return staff.VoteCount;
16                     }
17                     catch (DbUpdateException)
18                     {
19                         Thread.Sleep(random.Next(1, 10));
20                     }
21                 }
22             }
23         }

好嘛,這下寫完了開始使用,也沒啥問題。APP呢也沒上線,沒啥用戶,就幾個開發和公司內部的人點來點去...

 

那么,問題來了。比如一個管理員錄入員工信息的方法,基本需求是:管理員提前錄入所有簽約員工信息,員工注冊系統時輸入手機號即被識別為已簽約員工,個人信息自動獲取。那這個方法肯定也是需要加上lock的,因為我們會同時存在多個管理員錄入信息,要保證不重復錄入,只有加上lock...

我想問的是:

1.有木有哪位大神能簡單的歸納一下什么樣的上下文中需要加lock,需要做並發處理?是不是所有可能並發的方法都需要?

2.管理員的操作算不算並發操作?系統目前允許同一個管理員賬戶在多端登錄操作,那是不是管理員操作的所有方法都需要做並發控制?

3.由2引申到員工用戶與企業用戶,如果我開放允許這些用戶的賬戶在多端登錄系統,是不是都算並發?

4.再來隨便挑一個方法,比如注冊方法,用戶名為郵箱,要求不重復,然而我的數據庫字段並沒有做唯一約束,是不是也得加上lock?因為是有可能同時很多用戶用同一個郵箱注冊的,或者客戶端沒寫好,多次重復點擊了注冊按鈕...

5.那么我很憂心的是,是不是所有方法都成了可能被並發的方法?

...

博主編程水平有限,團隊也很小,感覺知識很難擴充。如果上述內容很白很菜(自己都這么覺得,感覺進了死胡同又繞不出來),請一笑了之,也歡迎指點一二,感激不盡。

 

天天為項目忙碌,感覺自己的水平並沒有提高,迷茫ing...請各位指點迷津


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM