7

सभी, मैं काम दिया गया है एक बड़ी सी # आवेदन मल्टी-सूत्र में बाँधना। ऐसा करने के लिए मैंने async/await का उपयोग करना चुना है। मैं को प्रगति रिपोर्ट करने के लिए IProgress<T> के उपयोग से अच्छी तरह परिचित यूआई (के यूआई को यह 'धक्का' जानकारी कॉल) कर रहा हूँ, लेकिन मैं यह भी (यूआई से करने के लिए 'पुल' डेटा की जरूरत है मेरे मामले एक SpreadsheetGear कार्यपुस्तिका में, जिसमें डेटा होता है)। यह इस दो तरह से बातचीत है कि मैं पर कुछ सलाह चाहते है ...मल्टी-थ्रेडिंग एक बड़े सी # आवेदन async का उपयोग करते हुए/इंतजार

वर्तमान में मैं एक क्लिक करें घटना आग प्रसंस्करण शुरू करने के लिए, और कोड निम्नलिखित संरचना है: ProcessScriptAsync में

CancellationTokenSource cancelSource; 
private async void SomeButton_Click(object sender, EventArgs e) 
{ 
    // Set up progress reporting. 
    IProgress<CostEngine.ProgressInfo> progressIndicator = 
     new Progress<CostEngine.ProgressInfo>(); 

    // Set up cancellation support, and UI scheduler. 
    cancelSource = new CancellationTokenSource(); 
    CancellationToken token = cancelSource.Token; 
    TaskScheduler UIScheduler = TaskScheduler.FromCurrentSynchronizationContext(); 

    // Run the script processor async. 
    CostEngine.ScriptProcessor script = new CostEngine.ScriptProcessor(this); 
    await script.ProcessScriptAsync(doc, progressIndicator, token, UIScheduler); 

    // Do stuff in continuation... 
    ... 
} 

फिर, मैं निम्नलिखित है:

public async Task ProcessScriptAsync(
    SpreadsheetGear.Windows.Forms.WorkbookView workbookView, 
    IProgress<ProgressInfo> progressInfo, 
    CancellationToken token, 
    TaskScheduler UIScheduler) 
{ 
    // This is still on the UI thread. 
    // Here do some checks on the script workbook on the UI thread. 
    try 
    { 
     workbookView.GetLock(); 
     // Now perform tests... 
    } 
    finally { workbookView.ReleaseLock(); } 

    // Set the main processor off on a background thread-pool thread using await. 
    Task<bool> generateStageTask = null; 
    generateStageTask = Task.Factory.StartNew<bool>(() => 
     GenerateStage(workbookView, 
      progressInfo, 
      token, 
      UIScheduler)); 
    bool bGenerationSuccess = await generateStageTask; 

    // Automatic continuation back on UI thread. 
    if (!bGenerationSuccess) { // Do stuff... } 
    else { 
    // Do other stuff 
    } 
} 

यह अब तक ठीक लग रहा है। समस्या मैं अब विधि GenerateStage, जो अब एक पृष्ठभूमि धागा पूल धागा

private bool GenerateStage(
    SpreadsheetGear.WorkbookView workbookView, 
    IProgress<ProgressInfo> progressInfo, 
    CancellationToken token, 
    TaskScheduler scheduler) 
{ 
    ... 
    // Get the required data using the relevant synchronisation context. 
    SpreadsheetGear.IWorksheet worksheet = null; 
    SpreadsheetGear.IRange range = null; 
    Task task = Task.Factory.StartNew(() => 
    { 
     worksheet = workbookView.ActiveWorksheet; 
     range = worksheet.UsedRange; 
    }, CancellationToken.None, 
     TaskCreationOptions.None, 
     scheduler); 
    try 
    { 
     task.Wait(); 
    } 
    finally 
    { 
     task.Dispose(); 
    } 

    // Now perform operations with 'worksheet'/'range' on the thread-pool thread... 
} 

पर चलाया जाता है इस विधि मैं यूआई कई बार करने के लिए यूआई से डेटा निकाल सकते हैं और डेटा लिखने की ज़रूरत में है। लेखन के लिए मैं स्पष्ट रूप से 'progressInfo' का उपयोग कर सकता हूं, लेकिन यूआई से खींचने वाली जानकारी को कैसे संभालना है। यहां, मैंने यूआई थ्रेड सिंक्रनाइज़ेशन संदर्भ का उपयोग किया है, लेकिन यह कई बार किया जाएगा। क्या इन परिचालनों को करने का कोई बेहतर तरीका है/क्या मेरे वर्तमान दृष्टिकोण में कोई दोष है?

नोट। स्पष्ट रूप से मैं Task.Factory.StartNew(...) कोड को एक पुन: प्रयोज्य विधि में लपेटूंगा, उपरोक्त स्पष्ट रूप से पैदावार के लिए दिखाया गया है।

+1

तो, 'WorkbookView' यूआई धागा से पहुँचा जा करने के लिए है, लेकिन' IWorksheet' और 'IRange' एक और धागे से इस्तेमाल किया जा सकता? क्या आप केवल दो ऑब्जेक्ट्स को 'जेनरेटस्टेज()' में नहीं पारित कर सकते थे? – svick

+1

'workbookViewAsync = workbookView' नहीं * एक प्रतिलिपि बनायेगा, यह सिर्फ * संदर्भ * को दूसरे चर में कॉपी करेगा। लेकिन नया चर अभी भी पुरानी वस्तु को इंगित करेगा। – svick

+0

पहला पोस्ट एक उचित सुझाव है, लेकिन 'वर्कशीट' या 'इरेंज' पर संचालन करने के लिए आपको कार्यपुस्तिका सेट या 'वर्कबुक व्यू' पर 'गेटलॉक() 'कॉल करना होगा, इसका मतलब है कि' वर्कबुक व्यू 'का उपयोग करना है यूआई थ्रेड पर बनाया गया। – MoonKnight

उत्तर

2

आप लगातार आगे पीछे यूआई और थ्रेड पूल धागे के बीच जा रहे हैं, अपने कोड थोड़ा गंदा होने जा रहा है।

आपके पास अनिवार्य रूप से दो विकल्प हैं: क्या आपका "सामान्य" संदर्भ यूआई थ्रेड (जैसा कि आपके पास है) के लिए निर्धारित थ्रेड पूल थ्रेड हो, या आपका "सामान्य" संदर्भ निर्धारित संस्करणों के साथ यूआई थ्रेड हो एक थ्रेड पूल थ्रेड के लिए।

मैं आमतौर पर उत्तरार्द्ध पसंद करता हूं, क्योंकि आप एक विशिष्ट TaskScheduler पर Task.Factory.StartNew के बजाय Task.Run का उपयोग कर सकते हैं। लेकिन किसी भी तरह से, कोड थोड़ा गन्दा होने जा रहा है।

+0

मुझे पूरी तरह से आश्वस्त नहीं है कि मैं जो कर रहा हूं वह सबसे अच्छा तरीका है, लेकिन मैं वास्तव में एक और नहीं देख सकता। कोड पुराना और जटिल है - बहु-थ्रेडिंग का समर्थन करने के लिए फिर से डिज़ाइनिंग, न केवल अनौपचारिक लगता है (क्योंकि कोड अच्छी तरह से अपना काम करने के लिए लिखा गया है), लेकिन इस मामले में मुझे नहीं लगता कि यह मेरी मदद कैसे करेगा। मैं मुख्य रूप से 'टास्क' की संख्या से अधिक चिंतित हूं, मैं यूआई से डेटा खींचने के लिए कताई कर रहा हूं। स्पष्ट रूप से इन धागे को उखाड़ फेंकने के लिए एक अपरिहार्य उपरांत होगा - मुझे किस तरह का ओवरहेड अभी तक नहीं पता ... आपके समय के लिए धन्यवाद। – MoonKnight

0

मैंने स्प्रेडशीट गियर कार्यपुस्तिका के साथ काम नहीं किया, लेकिन मुझे लगता है कि इसमें एक ईवेंट तंत्र है जिसका उपयोग आप कस्टम ऑब्जेक्ट में प्रासंगिक डेटा संग्रहीत करने के लिए कर सकते हैं, जिसे आप UISynchronizationContext के बाहर से एक्सेस कर सकते हैं, इसमें जिस तरह से आप कार्यपुस्तिका यूआई नियंत्रण से दृढ़ता से बाध्य होने से बचते हैं। यह आपको

Task task = Task.Factory.StartNew(() => 
{ 
    worksheet = workbookView.ActiveWorksheet; 
    range = worksheet.UsedRange; 
}, CancellationToken.None, 
    TaskCreationOptions.None, 
    scheduler); 
try 
{ 
    task.Wait(); 
} 
finally 
{ 
    task.Dispose(); 
} 

जेनरेटस्टेज विधि से भाग के साथ यूआई थ्रेड को अवरुद्ध करने से बचने की अनुमति देगा।

लेकिन फिर, मेरे सुझाव SpreadsheetGear कार्यपुस्तिका नियंत्रण के बारे में कुछ मान्यताओं, यह गलत हो सकता है पर आधारित है।

+1

आप पुष्टि करने के लिए [प्रलेखन] (http://www.spreadsheetgear.com/support/help/spreadsheetgear.net.3.0/SpreadsheetGear~SpreadsheetGear.Windows.Forms.WorkbookView.html) देख सकते हैं या पुष्टि कर सकते हैं या अपनी धारणाओं का खंडन करें। – svick