में एक लंबे समय तक चलने वाले कार्य को छोड़कर हमारा आवेदन टीपीएल का उपयोग धारावाहिक (संभावित रूप से) काम की लंबी चल रही इकाइयों को क्रमबद्ध करने के लिए करता है। काम (कार्य) का निर्माण उपयोगकर्ता संचालित है और किसी भी समय रद्द किया जा सकता है। एक उत्तरदायी यूजर इंटरफेस रखने के लिए, यदि काम का वर्तमान टुकड़ा अब आवश्यक नहीं है, तो हम जो भी कर रहे थे उसे त्यागना चाहते हैं, और तुरंत एक अलग कार्य शुरू करें।टीपीएल
कार्य कुछ इस तरह ऊपर पंक्तिबद्ध कर रहे हैं:
private Task workQueue;
private void DoWorkAsync
(Action<WorkCompletedEventArgs> callback, CancellationToken token)
{
if (workQueue == null)
{
workQueue = Task.Factory.StartWork
(() => DoWork(callback, token), token);
}
else
{
workQueue.ContinueWork(t => DoWork(callback, token), token);
}
}
DoWork
विधि एक लंबी चलने वाली कॉल होता है, इसलिए यह उतना ही आसान नहीं है लगातार token.IsCancellationRequested
की स्थिति जांचने और प्रति सहिष्णु के रूप में यदि/जब एक रद्द का पता चला है । लंबे समय तक चलने वाला कार्य टास्क निरंतरता को तब तक अवरुद्ध कर देगा जब तक यह कार्य समाप्त न हो जाए, भले ही कार्य रद्द हो जाए।
मैं इस मुद्दे के आसपास काम करने के लिए दो नमूना तरीकों के साथ आया हूं, लेकिन मुझे विश्वास नहीं है कि या तो उचित हैं। मैंने यह दिखाने के लिए सरल कंसोल अनुप्रयोग बनाए कि वे कैसे काम करते हैं।
ध्यान देने योग्य महत्वपूर्ण बात यह है कि मूल कार्य से पहले निरंतरता आग पूर्ण करती है।
प्रयास # 1: एक आंतरिक कार्य
static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();
var token = cts.Token;
token.Register(() => Console.WriteLine("Token cancelled"));
// Initial work
var t = Task.Factory.StartNew(() =>
{
Console.WriteLine("Doing work");
// Wrap the long running work in a task, and then wait for it to complete
// or the token to be cancelled.
var innerT = Task.Factory.StartNew(() => Thread.Sleep(3000), token);
innerT.Wait(token);
token.ThrowIfCancellationRequested();
Console.WriteLine("Completed.");
}
, token);
// Second chunk of work which, in the real world, would be identical to the
// first chunk of work.
t.ContinueWith((lastTask) =>
{
Console.WriteLine("Continuation started");
});
// Give the user 3s to cancel the first batch of work
Console.ReadKey();
if (t.Status == TaskStatus.Running)
{
Console.WriteLine("Cancel requested");
cts.Cancel();
Console.ReadKey();
}
}
यह काम करता है, लेकिन "innerT" टास्क मेरे लिए अत्यंत kludgey महसूस करता है। मुझे अपने कोड के सभी हिस्सों को दोबारा करने के लिए मजबूर करने की भी कमी है जो इस तरह से काम को कतार में रखता है, एक नए कार्य में सभी लंबी चलने वाली कॉलों को लपेटने की आवश्यकता के द्वारा।
प्रयास # 2: TaskCompletionSource
static void Main(string[] args)
{ var tcs = new TaskCompletionSource<object>();
//Wire up the token's cancellation to trigger the TaskCompletionSource's cancellation
CancellationTokenSource cts = new CancellationTokenSource();
var token = cts.Token;
token.Register(() =>
{ Console.WriteLine("Token cancelled");
tcs.SetCanceled();
});
var innerT = Task.Factory.StartNew(() =>
{
Console.WriteLine("Doing work");
Thread.Sleep(3000);
Console.WriteLine("Completed.");
// When the work has complete, set the TaskCompletionSource so that the
// continuation will fire.
tcs.SetResult(null);
});
// Second chunk of work which, in the real world, would be identical to the
// first chunk of work.
// Note that we continue when the TaskCompletionSource's task finishes,
// not the above innerT task.
tcs.Task.ContinueWith((lastTask) =>
{
Console.WriteLine("Continuation started");
});
// Give the user 3s to cancel the first batch of work
Console.ReadKey();
if (innerT.Status == TaskStatus.Running)
{
Console.WriteLine("Cancel requested");
cts.Cancel();
Console.ReadKey();
}
}
संवारता फिर इस काम करता है, लेकिन अब मैं दो समस्याएं हैं:
एक) यह लगता है जैसे मैं कभी नहीं का उपयोग कर इसे परिणाम है द्वारा TaskCompletionSource कोस रहा हूँ, और जब मैंने अपना काम पूरा कर लिया है तो बस शून्य स्थापित करें।
बी) निरंतरता को व्यवस्थित करने के लिए मुझे काम के अद्वितीय कार्यसमूह स्रोत की पिछली इकाई पर एक हैंडल रखने की आवश्यकता है, और इसके लिए बनाए गए कार्य को नहीं। यह तकनीकी रूप से संभव है, लेकिन फिर घबराहट और अजीब लगता है।
यहां से कहाँ जाना है?
दोहराने के लिए, मेरा प्रश्न यह है कि: इन समस्याओं में से किसी एक को इस समस्या से निपटने के लिए "सही" तरीका है, या क्या कोई और सही/सुरुचिपूर्ण समाधान है जो मुझे समय से पहले लंबे समय तक चलने वाले कार्य को निरस्त करने और तुरंत शुरू करने की अनुमति देगा एक निरंतरता? मेरी वरीयता कम प्रभाव वाले समाधान के लिए है, लेकिन अगर यह सही काम है तो मैं कुछ बड़े रिफैक्टरिंग करने के इच्छुक हूं।
वैकल्पिक रूप से, टीपीएल नौकरी के लिए भी सही उपकरण है, या क्या मुझे एक बेहतर कार्य क्यूइंग तंत्र गुम है। मेरा लक्ष्य ढांचा .NET 4.0 है।
मैं भी प्रश्न पूछा यहाँ पर: http://social.msdn.microsoft.com/Forums/en/parallelextensions/thread/d0bcb415-fb1e-42e4-90f8-c43a088537fb –