我已經閱讀了很多關於在.NET 4.0中新的任務功能的一個或多個對象,但是我還沒有發現以下問題的解決方案:.NET 4.0的任務:同步上
我寫一個服務器應用程序處理來自多個用戶的請求,我想使用任務將這些請求分發到多個核心。但是,這些任務應該在對象上同步 - 對於開始的用戶 - 這樣每次只處理一個對象的任務。使用Task.ContinueWith()可以很容易實現,但也可以在多個對象上同步一個任務(例如,當用戶將資金轉移給另一個用戶時,變量應該在用戶A處遞減並在用戶B處遞增沒有其他任務干擾)。
所以,我的第一次嘗試是接收委託,創建任務並將它們存儲在字典中的類,並將對象作爲關鍵字進行同步。如果計劃了新任務,則可以使用Task.ContinueWith()將其附加到給定對象的最後一個任務。如果它應該在多個對象上同步,則使用TaskFactory.ContinueWhenAll()創建新任務。創建的任務存儲在字典中,用於與其同步的每個對象。 這是我的第一稿:
public class ActionScheduler:IActionScheduler
{
private readonly IDictionary<object, Task> mSchedulingDictionary = new Dictionary<object, Task>();
private readonly TaskFactory mTaskFactory = new TaskFactory();
/// <summary>
/// Schedules actions synchonized on one or more objects. Only one action will be processed for each object at any time.
/// </summary>
/// <param name="synchronisationObjects">Array of objects the current action is synchronized on</param>
/// <param name="action">The action that will be scheduled and processed</param>
public void ScheduleTask(object[] synchronisationObjects, Action action)
{
// lock the dictionary in case two actions are scheduled on the same object at the same time
// this is necessary since reading and writing to a dictionary can not be done in an atomic manner
lock(mSchedulingDictionary)
{
// get all current tasks for the given synchronisation objects
var oldTaskList = new List<Task>();
foreach (var syncObject in synchronisationObjects)
{
Task task;
mSchedulingDictionary.TryGetValue(syncObject, out task);
if (task != null)
oldTaskList.Add(task);
}
// create a new task for the given action
Task newTask;
if (oldTaskList.Count > 1)
{
// task depends on multiple previous tasks
newTask = mTaskFactory.ContinueWhenAll(oldTaskList.ToArray(), t => action());
}
else
{
if (oldTaskList.Count == 1)
{
// task depends on exactly one previous task
newTask = oldTaskList[0].ContinueWith(t => action());
}
else
{
// task does not depend on any previous task and can be started immediately
newTask = new Task(action);
newTask.Start();
}
}
// store the task in the dictionary
foreach (var syncObject in synchronisationObjects)
{
mSchedulingDictionary[syncObject] = newTask;
}
}
}
}
如果一個任務「multiSyncTask」是爲多個對象創建的,併爲每個對象的事後任務計劃爲這甚至工作。因爲它們都與multiSyncTask.ContinueWith()創建的,他們開始同步:
static void Main()
{
IActionScheduler actionScheduler = new ActionScheduler();
var syncObj1 = new object();
var syncObj2 = new object();
// these two start and complete simultaneously:
actionScheduler.ScheduleTask(new[] { syncObj1 },() => PrintTextAfterWait("1"));
actionScheduler.ScheduleTask(new[] { syncObj2 },() => PrintTextAfterWait("2"));
// this task starts after the first two and "locks" both objects:
actionScheduler.ScheduleTask(new[] { syncObj1, syncObj2 },() => PrintTextAfterWait("1 and 2"));
// these two - again - start and complete simultaneously after the task above:
actionScheduler.ScheduleTask(new[] { syncObj1 },() => PrintTextAfterWait("1"));
actionScheduler.ScheduleTask(new[] { syncObj2 },() => PrintTextAfterWait("2"));
}
static void PrintTextAfterWait(string text)
{
Thread.Sleep(3000);
Console.WriteLine(text);
}
你覺得 - 這是我的問題很好的解決方案?我對字典上的大鎖有點懷疑,但是如果兩個任務同時安排在一個對象上以防止競爭條件,就很有必要。當然,字典只是在創建任務所需的時間內被鎖定,而不是在處理時。
此外,我很想知道是否有任何已有的解決方案或編碼範例,可以更好地解決我的問題,使用.net 4.0我沒有找到的任務。
謝謝你和最誠摯的問候, 約翰內斯
是的,不知道鎖;它包裝了兩個`for-each`循環。 – IAbstract 2011-01-13 19:05:36