Ich habe versucht, Schreiboperation mit File IO-Operationen zu implementieren und diese Operationen in TransformBlock
eingekapselt, um diese Operation thread sicher zu machen, anstatt Sperrmechanismus zu verwenden.Speicherproblem in TPL Dataflow-Implementierung von IO-Lese-Schreibvorgang
Aber das Problem ist, dass, wenn ich versuche, sogar 5 Dateien parallel zu schreiben, gibt es einen Speicher außerhalb der Ausnahme und bei der Verwendung dieser Implementierung blockiert es UI-Thread. Die Implementierung erfolgt in Windows Phone-Projekt. Bitte schlagen Sie vor, was in dieser Implementierung falsch ist.
Datei IO Betrieb
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 Nutzungs
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..";
}
Speichern und Laden von Daten 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
{
}
}
Bearbeiten:
Der Grund, dass es Speicherausnahme hat, ist aus einem Grund, dass die Datenfolge, die ich nahm, zu groß ist. Die Zeichenfolge ist Link: http://1drv.ms/1QWSAsc
Aber das zweite Problem ist, dass, wenn ich kleine Daten auch dann hinzufügen, es UI-Thread blockiert. Führt Code auf dem UI-Profil eine Aufgabe aus?
Ich erkunde Wege, um IO-Operationen threadsicher zu machen, ohne den Sperrmechanismus zu verwenden. Um Nebenwirkungen der Verriegelung zu vermeiden. Wie Sie sagen, sollte ich die Anzahl der Blockerstellung reduzieren oder einen Diff-Ansatz verwenden. Kannst du einen Weg vorschlagen, dies besser zu machen oder einen neuen Weg, den ich mehr erkunden kann? –
@BalrajSingh TPL Dataflow verwendet intern noch Blöcke. Manuelle 'lock'-Anweisungen sind viel besser lesbar und viel effizienter. – VMAtm
Im letzten Beispiel ist' ConfigureAwait' falsch - das würde nicht kompilieren. Außerdem sollte 'ContinueWith' nicht verwendet werden. Wenn das op TPL Dataflow verwendet, wäre eine idiomatische Lösung ein finaler "ActionBlock" mit einem UI "TaskScheduler". –