2015-12-23 14 views
6

मैंने फाइल आईओ ऑपरेशंस का उपयोग करके रीड राइट ऑपरेशन को कार्यान्वित करने की कोशिश की है और इन परिचालनों को TransformBlock में encapsulated ताकि लॉकिंग तंत्र का उपयोग करने के बजाय इन ऑपरेशन थ्रेड को सुरक्षित बनाया जा सके।आईओ के टीपीएल डेटाफ्लो कार्यान्वयन में मेमोरी इश्यू लिखने के लिए ऑपरेशन

लेकिन समस्या यह है कि जब मैं समान रूप से 5 फाइलें लिखने की कोशिश करता हूं तो अपवाद से बाहर स्मृति होती है और इस कार्यान्वयन का उपयोग करने पर यह यूआई थ्रेड को अवरुद्ध कर रहा है। कार्यान्वयन विंडोज फोन प्रोजेक्ट में किया जाता है। कृपया सुझाव दें कि इस कार्यान्वयन में क्या गलत है।

फ़ाइल आईओ ऑपरेशन

public static readonly IsolatedStorageFile _isolatedStore = IsolatedStorageFile.GetUserStoreForApplication(); 
public static readonly FileIO _file = new FileIO(); 
public static readonly ConcurrentExclusiveSchedulerPair taskSchedulerPair = new ConcurrentExclusiveSchedulerPair(); 
public static readonly ExecutionDataflowBlockOptions exclusiveExecutionDataFlow 
    = new ExecutionDataflowBlockOptions 
{ 
    TaskScheduler = taskSchedulerPair.ExclusiveScheduler, 
    BoundedCapacity = 1 
}; 

public static readonly ExecutionDataflowBlockOptions concurrentExecutionDataFlow 
    = new ExecutionDataflowBlockOptions 
{ 
    TaskScheduler = taskSchedulerPair.ConcurrentScheduler, 
    BoundedCapacity = 1 
}; 

public static async Task<T> LoadAsync<T>(string fileName) 
{ 
    T result = default(T); 

    var transBlock = new TransformBlock<string, T> 
     (async fName => 
     { 
      return await LoadData<T>(fName); 
     }, concurrentExecutionDataFlow); 

    transBlock.Post(fileName); 

    result = await transBlock.ReceiveAsync(); 

    return result; 
} 

public static async Task SaveAsync<T>(T obj, string fileName) 
{ 
    var transBlock = new TransformBlock<Tuple<T, string>, Task> 
     (async tupleData => 
     { 
      await SaveData(tupleData.Item1, tupleData.Item2); 
     }, exclusiveExecutionDataFlow); 

    transBlock.Post(new Tuple<T, string>(obj, fileName)); 

    await transBlock.ReceiveAsync(); 
} 

MainPage.xaml.cs प्रयोग

private static string data = "vjdsskjfhkjsdhvnvndjfhjvkhdfjkgd" 
private static string fileName = string.Empty; 
private List<string> DataLstSample = new List<string>(); 
private ObservableCollection<string> TestResults = new ObservableCollection<string>(); 
private static string data1 = "hjhkjhkhkjhjkhkhkjhkjhkhjkhjkh"; 
List<Task> allTsk = new List<Task>(); 
private Random rand = new Random(); 
private string fileNameRand 
{ 
    get 
    { 
     return rand.Next(100).ToString(); 
    } 
} 

public MainPage() 
{ 
    InitializeComponent(); 

    for (int i = 0; i < 5; i ++) 
    { 
     DataLstSample.Add((i % 2) == 0 ? data : data1); 
    } 

} 

private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    AppIsolatedStore_TestInMultiThread_LstResultShouldBeEqual(); 
} 

public async void AppIsolatedStore_TestInMultiThread_LstResultShouldBeEqual() 
{ 
    TstRst.Text = "InProgress.."; 
    allTsk.Clear(); 

    foreach(var data in DataLstSample) 
    { 
     var fName = fileNameRand; 

     var t = Task.Run(async() => 
     { 
      await AppIsolatedStore.SaveAsync<string>(data, fName); 
     }); 

     TestResults.Add(string.Format("Writing file name: {0}, data: {1}", fName, data)); 
     allTsk.Add(t); 
    } 

    await Task.WhenAll(allTsk); 

    TstRst.Text = "Completed.."; 
} 

सहेजें और लोड डेटा Async

 /// <summary> 
     /// Load object from file 
     /// </summary> 
     private static async Task<T> LoadData<T>(string fileName) 
     { 

      T result = default(T); 

      try 
      { 
       if (!string.IsNullOrWhiteSpace(fileName)) 
       { 
        using (var file = new IsolatedStorageFileStream(fileName, FileMode.OpenOrCreate, _isolatedStore)) 
        { 
         var data = await _file.ReadTextAsync(file); 

         if (!string.IsNullOrWhiteSpace(data)) 
         { 
          result = JsonConvert.DeserializeObject<T>(data); 
         } 
        } 
       } 
      } 
      catch (Exception ex) 
      { 
       //todo: log the megatron exception in a file 
       Debug.WriteLine("AppIsolatedStore: LoadAsync : An error occured while loading data : {0}", ex.Message); 
      } 
      finally 
      { 

      } 

      return result; 
     } 


     /// <summary> 
     /// Save object from file 
     /// </summary> 
     private static async Task SaveData<T>(T obj, string fileName) 
     { 
      try 
      { 
       if (obj != null && !string.IsNullOrWhiteSpace(fileName)) 
       { 
        //Serialize object with JSON or XML serializer 
        string storageString = JsonConvert.SerializeObject(obj); 

        if (!string.IsNullOrWhiteSpace(storageString)) 
        { 
         //Write content to file 
         await _file.WriteTextAsync(new IsolatedStorageFileStream(fileName, FileMode.Create, _isolatedStore), storageString); 
        } 
       } 
      } 
      catch (Exception ex) 
      { 
       //todo: log the megatron exception in a file 
       Debug.WriteLine("AppIsolatedStore: SaveAsync : An error occured while saving the data : {0}", ex.Message); 
      } 
      finally 
      { 
      } 
     } 

संपादित करें:

कारण यह है कि इसमें स्मृति अपवाद है क्योंकि एक कारण यह है कि मैंने जो डेटा स्ट्रिंग लिया वह बहुत बड़ा है। स्ट्रिंग लिंक है: http://1drv.ms/1QWSAsc

लेकिन दूसरी समस्या यह है कि यदि मैं छोटा डेटा भी जोड़ता हूं तो यह यूआई थ्रेड को अवरुद्ध कर रहा है। क्या कोड यूआई ट्रेड पर कोई काम कर रहा है?

उत्तर

1

नहीं, आप समवर्ती जोड़ी का उपयोग करते हैं जो इसके कार्यों के लिए डिफ़ॉल्ट थ्रेड पूल का उपयोग करता है, और आप Run विधि के साथ कार्यों को तुरंत चालू करते हैं, इसलिए समस्या यहां नहीं है।

var transBlock = new TransformBlock<string, T> 
    (async fName => 
    { 
     // process file here 
    }, concurrentExecutionDataFlow); 

आप वास्तव में नहीं बनाना चाहिए transBlock हर बार: लेकिन कोड आप यहाँ दो मुख्य खतरों है। TPL Dataflow का मुख्य विचार यह है कि आप एक बार ब्लॉक बना रहे हैं और उसके बाद उनका उपयोग कर रहे हैं। तो आपको अपने ऐप को तत्काल अवरुद्ध करने वाले ब्लॉकों की संख्या कम करने के लिए दोबारा करना चाहिए, अन्यथा यह नहीं है कि TPL Dataflow का उपयोग किया जाना चाहिए।

आपके कोड में एक अन्य खतरा यह है कि आप स्पष्ट रूप से धागे को अवरुद्ध कर रहे हैं!

// Right here 
await Task.WhenAll(allTsk); 
TstRst.Text = "Completed.."; 

डिफ़ॉल्ट it captures the synchronization context द्वारा के रूप में धागा, एक synchronious ईवेंट हैंडलर ब्लॉकों से एक async void विधि से कार्य के लिए एक await कॉलिंग। सबसे पहले, async void should be avoided। दूसरा, यदि आप async हैं, तो आप should be async all the way, इसलिए ईवेंट हैंडलर भी एसिंक होना चाहिए। तीसरा, आप अपने यूआई या use current synchronization context को अपडेट करने के लिए continuation for your task का उपयोग कर सकते हैं। 1 अभी भी समस्या जारी रहती है

// store the sync context in the field of your form 
SynchronizationContext syncContext = SynchronizationContext.Current; 

// avoid the async void :) 
public async Task AppIsolatedStore_TestInMultiThread_LstResultShouldBeEqual() 

// make event handler async - this is the only exception for the async void use rule from above 
private async void Button_Click(object sender, RoutedEventArgs e) 

// asynchronically wait the result without capturing the context 
await Task.WhenAll(allTsk).ContinueWith(
    t => { 
    // you can move out this logic to main method 
    syncContext.Post(new SendOrPostCallback(o => 
     { 
      TstRst.Text = "Completed.."; 
     })); 
    } 
); 
+0

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

+0

@ बलराजसिंह टीपीएल डेटाफ्लो अभी भी आंतरिक रूप से ब्लॉक का उपयोग करता है। मैन्युअल 'लॉक' कथन अधिक पढ़ने योग्य हैं, और अधिक कुशल – VMAtm

+1

अंतिम उदाहरण में, 'कॉन्फ़िगरएवाइट' गलत है - यह संकलित नहीं होगा। साथ ही, 'जारी रखें' का उपयोग नहीं किया जाना चाहिए। यदि ओपी टीपीएल डेटाफ्लो का उपयोग कर रहा है, तो एक और बेवकूफ समाधान यूआई 'टास्कशेड्यूलर' के साथ अंतिम 'एक्शनब्लॉक' होगा। –

0

क्या आपने ExecutionDataflowBlockOptions पर BoundedCapacity पैरामीटर के साथ खेलने का प्रयास किया है?

[...] सीमांकन एक dataflow नेटवर्क में उपयोगी असीम स्मृति से बचने के लिए विकास है: Introduction to TPL ब्लॉक क्षमता के बारे में यह उल्लेख है। यह विश्वसनीयता कारणों के लिए बहुत महत्वपूर्ण हो सकता है, अगर वहाँ है एक संभावना है कि उत्पादकों बहुत तेजी से से उपभोक्ताओं को यह संसाधित कर सकते हैं डेटा पैदा हो सकते हैं ...

क्रमांक इस विकल्प को इस सीमा की कतार उपयोग करने की कोशिश करने का सुझाव संसाधित वस्तुओं और देखें कि क्या यह आपकी मेमोरी समस्याओं के साथ मदद करता है

+0

मैं निर्धारित किया है BoundingCapacity:

तो, अपने कोड कुछ इस तरह होना चाहिए। –

संबंधित मुद्दे