C# synchronize wpf - c#

I have a project at school to make a WPF project which makes encryption and decryption of an input text. I want the application to be responsive but it always freeze.
I want to use TPL and I use TaskScheduler.FromCurrentSynchronizationContext() but it is not working. I don't want to use Dispatcher or something else what is specific only to WPF.
tokenSource = new CancellationTokenSource();
int lineCount = textBoxInput.LineCount;
string encryptTextInput = "";
List<string> listText = new List<string>();
List<Task> listTask = new List<Task>();
var ui = TaskScheduler.FromCurrentSynchronizationContext();
for (int cnt = 0; cnt < lineCount; cnt++)
{
encryptTextInput = textBoxInput.GetLineText(cnt);
listText.Add(encryptTextInput);
}
for (int cnt = 0; cnt < lineCount; cnt++)
{
int line = cnt;
var myTask = Task.Factory.StartNew(result =>
{
return EncryptDecrypt.Encrypt(listText[line]);
}, tokenSource.Token);
listTask.Add(myTask);
var display = myTask.ContinueWith(resultTask =>
textBoxOutput.Text += myTask.Result.ToString(), CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, ui);
var displayCancel = myTask.ContinueWith(resultTask =>
textBoxOutput.Text += myTask.Result.ToString(), CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled, ui);
}

Refactored method which relates to Encryption. Please, see the comments related to the code below:
private async void buttonEncrypt_Click(object sender, RoutedEventArgs e)
{
string elapsedTime = string.Empty;
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
tokenSource = new CancellationTokenSource();
int lineCount = textBoxInput.LineCount;
var outputResult = String.Empty;
for (int cnt = 0; cnt < lineCount; cnt++)
{
var lineToProcess = textBoxInput.GetLineText(cnt);
//Code inside task will work in thread from thread pool, so the UI thread shouldn't be blocked
string result = await Task.Run(() =>
EncryptDecrypt.Encrypt(lineToProcess), tokenSource.Token);
outputResult += result;
}
//UI thread: when completed update the UI with encrypted text.
textBoxOutput.Text = outputResult;
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
elapsedTime = String.Format("{0:00}:{1:00}:{2:00}:{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
time.Content = elapsedTime;
}
A couple of comments related to the code above.
The code working in the following way:
Read lines from textbox line by line.
Processes each line one by one
(in thread pool context) in order the lines are in input
When processing of all lines completed, add the result of encryption to the
output textbox
The problem in previous code was that the UI thread was accessing too frequently and this lead to UI freezing during processing.
Now the processing is going in background thread and rendered on UI only when all processing completes.
Also, I recommend you to add some kind of indicator to inform the user that the input is processing: progress bar or something other.

Related

Good way to make Userdialog.Instance.Progress wait for method to execute C# Xamarin

I'm trying to show a progress dialog showing the percent done with the method to wait everything + an await Task.Delay(20); And an await for the method I want to execute. Now I notice that with that task.delay the execution takes much longer.
What I want to achieve instead is that the progress.dialog calculates how long the method takes instead of putting a delay on it because this works a bit more slowly.
What are my options in this?
This is my code
private async Task DownloadAllAlert()
{
//alert to download everything
bool result = await DisplayAlert("Download", "Do you want to download everything?", "Yes", "No"); ;
//alert is user chose yes
if (result)
{
// loading dialog in percentage till downloading is done
using (var progress = UserDialogs.Instance.Progress("Loading..."))
{
for (var i = 0; i < 100; i++)
{
progress.PercentComplete = i;
await Api.DownloadAll();
await Task.Delay(20);
}
}
}
}
try using Task in c#.
using (var progress = UserDialogs.Instance.Progress("Loading..."))
{
await LoadData(ref progress);
}
call this function
public async Task LoadData(ref IProgressDialog progress);
{
//await Task.Yield(); //add this line of code if on ios didnt work
Task task1 = new Task(() =>
{
for (int i = 0; i < 50 ; i++) // loop untill 50% then increase sleeping thread time
{
progress.PercentComplete = i;
//sleeping for 1 second
Thread.Sleep(1000);
}
for (int i = 50; i < 100; i++) // loop untill 99% then stop
{
progress.PercentComplete = i;
//sleeping for 2 second
Thread.Sleep(2000);
}
Console.WriteLine("Task 1 complete");
});
Task task2 = new Task(() =>
{
await Api.DownloadAll();
Console.WriteLine("Task 2 complete");
});
//starting the tasks
task1.Start();
task2.Start();
Task.WaitAny(task2);
progress.PercentComplete = 100; // when task2 finish put it 100%
}

Pause/resume a thread in C#

I try to pause all my threads when I reach a certain value but I can't do it.
I would like that when I reach this value all threads are paused for 10 seconds and after these 10 seconds all threads start again.
I tried that with : Threads.Sleep(); | Threads.Interrupt(); and Threads.Abort(); but nothing work.
I tried what you can see in the code below.
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
Threads.Add(new Thread(new ThreadStart(example)));
Threads[i].Start();
}
for (int i = 0; i < Threads.Count; i++)
Threads[i].Join();
}
static void example()
{
while (true)
{
Console.WriteLine(value++);
checkValue();
}
}
public static void checkValue()
{
if (value% 1000 == 0 && value!= 0)
{
for (int i = 0; i < Threads.Count; i++)
Threads[i].Interrupt();
Thread.Sleep(1000);
for (int i = 0; i < Threads.Count; i++)
Threads[i].Resume();
}
}
Here is an example of pausing some threads cooperatively, by using the PauseTokenSource + PauseToken pair from Stephen Cleary's AsyncEx.Coordination package. This example shows also the use of the analogous CancellationTokenSource + CancellationToken pair, that inspired the creation of the aforementioned pausing mechanism.
var pts = new PauseTokenSource() { IsPaused = true };
var cts = new CancellationTokenSource();
int value = 0;
// Create five threads
Thread[] threads = Enumerable.Range(1, 5).Select(i => new Thread(() =>
{
try
{
while (true)
{
cts.Token.ThrowIfCancellationRequested(); // self explanatory
pts.Token.WaitWhilePaused(cts.Token); // ...and don't wait if not paused
int localValue = Interlocked.Increment(ref value);
Console.WriteLine($"Thread #{i}, Value: {localValue}");
}
}
catch (OperationCanceledException) // this exception is expected and benign
{
Console.WriteLine($"Thread #{i} Canceled");
}
})).ToArray();
// Start the threads
foreach (var thread in threads) thread.Start();
// Now lets pause and unpause the threads periodically some times
// We use the main thread (the current thread) as the controller
Thread.Sleep(500);
pts.IsPaused = false;
Thread.Sleep(1000);
pts.IsPaused = true;
Thread.Sleep(1000);
pts.IsPaused = false;
Thread.Sleep(1000);
pts.IsPaused = true;
Thread.Sleep(500);
// Finally cancel the threads and wait them to finish
cts.Cancel();
foreach (var thread in threads) thread.Join();
You may need to read this first, to get a grasp on the model used by the .NET platform for cooperative cancellation. Cooperative "pausation" is very similar.

How can I insert a delay between a List of Task<int>?

I have a loop that creates 5 Tasks. How can I insert a Delay of 5 seconds between each Task. I don't know how to fit Task.Delay(5000) in there.
var tasks = new List<Task<int>>();
for (var i = 0; i < 5; i++)
{
tasks.Add(ProcessQueueAsync());
}
await Task.WhenAll(tasks);
My ProcessQueAsync method calls a server, retrieves data and returns and int.
private async Task<int> ProcessQueAsync()
{
var result = await CallToServer();
return result.Count;
}
for (var i = 0; i < 5; i++)
{
tasks.Add(ProcessQueueAsync());
await Task.Delay(5000);
}
Or:
for (var i = 0; i < 5; i++)
{
await ProcessQueueAsync();
await Task.Delay(5000);
}
Depending on that you want.
If you want the tasks to run one after the other, with a 5 second delay, you should perhaps look at Task.ContinueWith instead of using Task.WhenAll. This would allow you to run tasks in serial rather than in parallel.

What is faster and more efficient - begininvoke or synchronisecontext.post?

Did anyone tried to find out - what is faster and what is more efficient (less objects created and thus less GC is involved) - control.BeginInvoke or SynchroniseContext.Post ?
WPF, C#, .NET 4
I'd appreciate responses with practical backing rather than "I think" or "I heard somewhere"..
Cheers
P.S. I am going to post a number of messages to few controls and I want it to be max efficient and fast (few hundred updates / sec). I know .NET can handle this (I did it before) but now I want it to be as fast as possible...
Firstly, there is no Control.BeginInvoke in WPF (that's winforms you're thinking of). Secondly, SynchronizationContext is an abstraction over whatever synchronization mechanism the current platform provides. In the case of WPF, it's an abstraction over the Dispatcher. Theoretically you pay a small price for using the abstraction rather than directly using the Dispatcher. But the abstraction is there for a good reason - sometimes you need to write thread synchronization code that is independent of the platform. If you don't then by all means use the Dispatcher directly.
The BeginInvoke is 42.8% faster than SynchronizationContext.Post on my i7 desktop.
The results are:
Post Send Diff ms Ratio
1280866 925416 35.00 -38.4%
1192232 916251 27.00 -30.1%
1338990 876215 46.00 -52.8%
1394783 863241 53.00 -61.6%
1332485 1046789 28.00 -27.3%
1335241 895784 43.00 -49.1%
1267470 1064894 20.00 -19.0%
1308461 884136 42.00 -48.0%
1321243 850704 47.00 -55.3%
1313230 896469 41.00 -46.5%
The code :
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.RealTime;
}
Thread th;
DispatcherSynchronizationContext ctx;
protected override void OnContentRendered(EventArgs e)
{
base.OnContentRendered(e);
Thread.CurrentThread.Priority = ThreadPriority.Highest;
ctx = new DispatcherSynchronizationContext(this.Dispatcher);
th = new Thread(Start);
th.Start();
}
int MACRO = 10;
int TESTS = 10;
int LOOPS = 50000;
void Start()
{
Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
// flush just in case
for (int i = 0; i < 100; i++)
{
ctx.Post(Callback, 9999999);
this.Dispatcher.BeginInvoke(
new Action<object>((object state) => { txt2.Text = state.ToString(); }),
DispatcherPriority.Send, 9999999);
}
Thread.Sleep(1000);
// results
List<Tuple<long, long>> results = new List<Tuple<long, long>>();
// actual test
for (int x = 0; x < MACRO; x++)
{
Stopwatch sw = new Stopwatch();
// sync context post
long tick1, tick2;
for (int i = 0; i < TESTS; i++)
{
sw.Start();
for (int j = i; j < LOOPS + i; j++)
{
ctx.Post(Callback, j);
}
sw.Stop();
Thread.Sleep(1500);
}
tick1 = sw.ElapsedTicks;
// begin invoke
sw.Reset();
for (int i = 0; i < TESTS; i++)
{
sw.Start();
for (int j = i; j < LOOPS + i; j++)
{
this.Dispatcher.BeginInvoke(
new Action<object>((object state) => { txt2.Text = state.ToString(); }),
DispatcherPriority.Normal, j);
}
sw.Stop();
Thread.Sleep(1500);
}
tick2 = sw.ElapsedTicks;
// store results
results.Add(new Tuple<long, long>(tick1, tick2));
// display to make it less boring
this.Dispatcher.BeginInvoke(new Action(() => { txt3.Text += string.Format("{0} {1}. ", tick1, tick2); }));
Thread.Sleep(100);
}
StringBuilder sb = new StringBuilder();
foreach (var res in results)
sb.AppendLine(string.Format("{0}\t{1}\t{2:0.00}\t{3:0.0%}",
res.Item1, res.Item2, (res.Item1 - res.Item2) / 10000, res.Item2 != 0 ? 1.0 - res.Item1 / (double)res.Item2 : 0.0));
this.Dispatcher.BeginInvoke(
new Action(() => { txb1.Text = sb.ToString(); }));
}
void Callback(object state)
{
txt1.Text = state.ToString();
}
}

Long running process freezing UI, how to update with threading?

I've written this sample code for a long running process, but the Windows Form freezes until the process completes. How do I change the code so that the work runs in parallel?
var ui = TaskScheduler.FromCurrentSynchronizationContext();
Task t = Task.Factory.StartNew(delegate
{
textBox1.Text = "Enter Thread";
for (int i = 0; i < 20; i++)
{
//My Long Running Work
}
textBox1.Text = textBox1.Text + Environment.NewLine + "After Loop";
}, CancellationToken.None, TaskCreationOptions.None, ui);
You can use a continuation. I don't remember the exact syntax but it's something like:
textBox1.Text = "Enter Thread"; //assuming here we're on the UI thread
Task t = Task.Factory.StartNew(delegate
{
for (int i = 0; i < 20; i++)
{
//My Long Running Work
}
return result;
})
.ContinueWith(ret => textBox1.Text = textBox1.Text + Environment.NewLine + result,
TaskScheduler.FromCurrentSynchronizationContext());
An alternative would be something like:
Task t = Task.Factory.StartNew(delegate
{
YourForm.Invoke((Action)(() => textBox1.Text = "Enter Thread");
for (int i = 0; i < 20; i++)
{
//My Long Running Work
}
YourForm.Invoke((Action)(() => textBox1.Text = textBox1.Text + Environment.NewLine + result);},
CancellationToken.None, TaskCreationOptions.None);
Again, I don't remember the exact syntax but the idea is that you want to perform the long operation on a thread different than the UI thread, but report progress (including completion) on the UI thread.
By the way, the BackGroundWorker class would work very well here, too (I personally like it very much).

Categories