If I have the following:
public string DoSomethingQuick()
{
DoSomethingThatTakes10Minutes();
return "Process Started";
}
public void DoSomethingThatTakes10Minutes()
{
/// code to do something that takes 10 minutes
}
How can I alter DoSomethingQuick() so that it returns "Process Started" instantly instead of waiting for DoSomethingThatTakes10Minutes() to complete first?
One way you could solve this would be to use async and await, like so:
public void Main()
{
AsyncExample();
Console.WriteLine("prints first");
}
public async Task AsyncExample()
{
Task<string> executesSeparately = ExecutesSeparately();
string result = await longRunningTask;
Console.WriteLine(result);
}
public async Task<string> ExecutesSeparately()
{
await Task.Delay(2000);
return "prints second";
}
As you'll see in the output window, Console.WriteLine("prints first") is executed before AsyncExample() completes and writes a line.
Another way you could solve this is by using a BackgroundWorker.
public string DoSomethingQuick()
{
var backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += delegate(object s, DoWorkEventArgs args)
{
DoSomethingThatTakes10Minutes();
};
backgroundWorker.RunWorkerAsync();
return "Process Started";
}
Note that, in a lot of cases, separate threads won't be able to alter non-static objects created from the primary thread, so you'll either need to use the Dispatcher or contain the UI thread logic in a call to BackgroundWorker.ReportProgress(), which automagically works on the UI thread. That would look more like so:
var backgroundWorker = new BackgroundWorker() { WorkerSupportsCancellation = true };
backgroundWorker.ReportProgress += delegate(object s, ProgressChangedEventArgs e)
{
DoSomethingThatTakes10MinutesAndExecutedOnUiThread();
}
backgroundWorker.DoWork += delegate(object s, DoWorkEventArgs e)
{
backgroundWorker.ReportProgress(0); // the progress value is irrelevant
};
Beside the fact that is pretty ambiguous for a method which should be quick to contain something that should take a long time...
You can use a thread to do it
Thread t;
public string DoSomethingQuick()
{
t=new Thread(DoSomethingThatTakes10Minutes);
t.isBackground=true;
t.Start();
return "Process Started";
}
For more info about Threads: http://msdn.microsoft.com/it-it/library/system.threading.thread(v=vs.110).aspx
Related
I'm trying to execute a thread without blocking UI , I've used this code but when I execute my application , it won't execute the thread and nothing is shown after clicking on DoButton event
public void DoThread()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += MyFunctionDoThread;
var frame = new DispatcherFrame();
worker.RunWorkerCompleted += (sender, args) => {
frame.Continue = false;
};
worker.RunWorkerAsync();
Dispatcher.PushFrame(frame);
}
private void Dobutton_Click(object sender, RoutedEventArgs e)
{
DoThread(); // Process will be executed
}
public void MyFunctionDoThread()
{
// Some Tasks
ProcessStartInfo startInfo = new ProcessStartInfo();
Process.Start(startInfo);
// ...
}
How I can perform a task ( thread ) without blocking the UI?
You should really use Task/async/await for any background work. BackgroundWorker is rather old.
public async void Dobutton_Click(object sender, RoutedEventArgs e)
{
try{
var result = await Task.Run(MyFunctionDoThread);
// Update the UI, or otherwise deal with the result
}
catch{
// deal with failures, like showing a dialog to the user
}
}
how can I use it , the await require to return task action
await requires the method to be marked with async, it does not require the method to return a task. It is a guideline to return a task, so that the caller can deal with any failures. But for things like button event handlers you are at the end of the line, there is no one else to deal with any failure, so you should instead make sure you do it yourself with a try/catch.
i am trying to use a third party telnet library "active expert" for a basic telnet session.
in my UI code behind i have something like
private async void Button_Click(object sender, RoutedEventArgs e)
{
var ts = new TelnetService();
await ts.DoConnect(node);
}
and my TelnetService looks like this
public class TelnetService
{
private Tcp objSocket = new Tcp();
private NwConstants objConstants = new NwConstants();
public string Responses { get; set; }
private Timer timer1 = new Timer();
public TelnetService()
{
timer1.Elapsed += timer1_Elapsed;
timer1.Interval = 100;
timer1.Start();
}
void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (objSocket.ConnectionState == objConstants.nwSOCKET_CONNSTATE_CONNECTED)
{
if (objSocket.HasData())
{
Responses += objSocket.ReceiveString() + "\r\n";
}
}
}
public Task DoConnect(Node node)
{
return Task.Factory.StartNew(() =>
{
objSocket.Protocol = objConstants.nwSOCKET_PROTOCOL_TELNET;
objSocket.Connect(node.IP, 23);
while (true)
{
if ((Responses == null) || (!Responses.Contains(node.WaitString))) continue;
//do something
Responses = "";
break;
}
});
}
}
there are two important pieces of functionalities.
First in the timer1_Elapsed function which is process that will keeps on ruining and checks if there is data on socket, and if there is, it will append it to a string "Response". and i am using "timer" for it.
Second in the DoConnect function which will check the"Response" string for a certain input. for this i am using async await and Task.
in a nutshell first one accumulating the Response and Second one checking the Response.
Problem is that it looks like the timer code in general and
objSocket.ReceiveString()
line specifically is causing the UI thread to halt for several seconds. which means after clicking the button i cannot move my main form on the screen however the code is running in a separate thread.
i have tried using pure Thread for this but it didn't helped either.
update
instead of timer i am using a method AccumulateResponse
public static void AccumulateResponse()
{
while (true)
{
if (objSocket.ConnectionState == objConstants.nwSOCKET_CONNSTATE_CONNECTED)
{
if (objSocket.HasData())
{
Responses += objSocket.ReceiveString() + "\r\n";
}
}
}
}
and calling it like
var t = new Task(TelnetService.AccumulateResponse);
t.Start();
await TelnetService.DoConnect(node);
still no luck
The DoConnect isn't your problem. It is your Timer Elapsed Event handler.
The timer elapsed event is NOT asynchronous. Only the DoConnect is.
If there is no asynchronous version of ReceiveString() from your third party lib, then use Task.Run there as well inside of an async timer1_elapsed method.
I have an UI, a custom class, and a thread. I want to run the custom class completely in a separate thread. Is there a clean way of doing this?
For example. On the MainForm below, when UI calls _threadOneClass.Sleep, I need the UI to go to the spawned ThreadOne and invoke the Sleep method in ThreadOne, not in the main thread.
Basically, all method calls in MyClass need to be executed in ThreadOne, not in main thread. It is like, the MyClass runs on its own "process", while still visible to be called from MainForm.
The MainForm has 3 buttons, and 1 textbox for logging.
I was thinking of deriving the Thread class, but it is sealed. So deriving is definitely a wrong way per Microsoft.
Help dear experts?
Here is the output (MainThread ID=10, ThreadOne ID=11)
MyClass instantiated
Starting ThreadOne
11-Run.start
Sleeping ThreadOne
10-Run.sleep for 3000 'Need this to run on ThreadID 11
10-Run.woke up 'Need this to run on ThreadID 11
Stopping ThreadOne
11-Run.done
Here is how the code look like.
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private Thread _threadOneThread;
private MyClass _threadOneClass;
private void btnThreadOneCreate_Click(object sender, EventArgs e)
{
_threadOneClass = new MyClass(this);
_threadOneThread = new Thread(new ThreadStart(_threadOneClass.Run));
_threadOneThread.Start();
}
private void btnThreadOneStop_Click(object sender, EventArgs e)
{
_threadOneClass.IsRunning = false;
}
private void btnThreadOneSleep_Click(object sender, EventArgs e)
{
_threadOneClass.Sleep(3000);
}
public void Log(string txt)
{
MainForm.SetText(txtLog, txt);
}
internal static void SetText(Control ctl, string val)
{
if (ctl.InvokeRequired)
ctl.Invoke((MethodInvoker)delegate() { ctl.Text += Environment.NewLine + val; });
else
ctl.Text += Environment.NewLine + val;
}
}
class MyClass
{
public MyClass(MainForm frm)
{
_mainForm = frm;
}
private MainForm _mainForm;
public bool IsRunning = true;
public void Run()
{
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.start");
while (IsRunning) { }
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.done");
}
public void Sleep(int milliseconds)
{
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.sleep for " + milliseconds.ToString());
Thread.Sleep(milliseconds);
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.woke up");
}
}
Threads allow you to run heavy operations while you continue doing other things. In the case of user interfaces (your scenario), asynchronous behavior is almost always necessary as blocking the UI thread will cause to be unresponsive to the user and just isn't an option.
Luckily, the folks at Microsoft has made it extremely easy to write the same code, but in an asynchronous manner. I usually use Tasks because I like the control you get over the operation as well as the ContinueWith() lets you control what you do with the result should you need to propagate data back to the calling thread. If you prefer to use threads, ThreadPool.QueueUserWorkItem is just as easy.
Any operation you do not want to block the UI thread wrap it like this,
Task.Factory.StartNew(() => Object.PerformOperation());
or
ThreadPool.QueueUserWorkItem(new WaitCallback((x) => Object.PeroformOperation()));
I find this allows me to write the same exact code, but without blocking the UI thread. If you have several statements to execute you can use a block as well.
Task.Factory.StartNew(() =>
{
// do something
// do more stuff
// done
}).ContinueWith((completedTask) =>
{
// if you were computing a value with the task
// you can now do something with it
// this is like a callback method, but defined inline
// use ui's dispatcher if you need to interact with ui compontents
UI.Label.Dispatcher.Invoke(new Action(() =>
UI.Item.Label.Text = completedTask.Result;
}
The upcoming async features that are being released in the next .net version actually streamline this even more! But since it uses tasks you will still want to get comfortable with using them.
// this will begin the operation, then return control back to the ui so it does not hang.
var result = await Object.PerformLongTask();
// once the long task is completed then it continues and you can use the result
UI.Item.Label = result;
To give a real example, here is some code from an FTP client I wrote which has has a WPF front end. When the start button is clicked the ftp transfer is launched in it's own task, then a while loop which updates the interface every half a second is launched in a task, so neither interferes with the interface thread. Again it's the same code, just wrapped in lambada's.
private void btnStart_Click(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(() =>
ftp.Mirror(#"C:\LocalFolder", "/RemoteFolder", 10));
Task.Factory.StartNew(() =>
{
while (true)
{
lbPercentSuccess.Dispatcher.Invoke(new Action(() =>
{
lbPercentSuccess.Content = ftp.FtpProgress.SuccessPercentage;
lbPercentError.Content = ftp.FtpProgress.ErrorPercentage;
lbPercentTotal.Content = ftp.FtpProgress.TotalPercentage;
lbDuration.Content = ftp.FtpProgress.Duration;
}));
Thread.Sleep(500);
}
});
}
This is not possible to my knowledge. You can only run and invoke individual methods or queue them on separate threads when need be. Setting an actual object on a separate thread defeats your purpose. This is because you only going to harness the benefits of multithreading when invoking a method on a separate thread not an object.
then reassign the del to MethodTwo... and so on. This is made easier if you conform to a method signature.
Possible solution:
Thread threadTest = new Thread(new ThreadStart(MethodOne));
threadTest = new Thread(new ThreadStart(MethodTwo));
threadTest.Start();
Or
Action del = TestClass.MethodOne;
IAsyncResult result = del.BeginInvoke(null, null);
Func<int,int> del = TestClass.MethodOne;
IAsyncResult result = del.BeginInvoke(11,null, null);
int value = del.EndInvoke(result);
It's not simple, but have a look at this. It's a nice explination of how to use cross thread communication.
http://www.codeproject.com/KB/cs/delegatequeue.aspx
So far, this is what I found (from iPhone development). The Run loop acts like a spine that invokes various methods. It is implemented like the following:
A more elegant solution is welcomed.
class MyClass
{
public MyClass(MainForm frm)
{
_mainForm = frm;
}
private MainForm _mainForm;
public bool IsRunning = true;
public void Run()
{
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.start");
while (IsRunning)
{
if (_runSleepMilliSeconds != null)
{
_Sleep(_runSleepMilliSeconds ?? 3000);
_runSleepMilliSeconds = null;
}
}
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.done");
}
private int? _runSleepMilliSeconds = null;
public void Sleep(int milliseconds)
{
_runSleepMilliSeconds = milliseconds;
}
private void _Sleep(int milliseconds)
{
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.sleep for " + milliseconds.ToString());
Thread.Sleep(milliseconds);
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.woke up");
}
}
How do I get results from the BackgroundWorker in this case? I'm also open to doing things in in alternative manner(such as not using BackgroundWorker). The goal is to do all my jobs in parallel, starting at the same time. I actually honestly don't know if all jobs will be completed in parallel using bw. I'm still learning this threading stuff. I'm using WPF/XAML (I'm pretty sure that makes a big difference on how threading type code is written).
namespace JobFactory
{
public partial class MainWindow : Window
{
MainWindow()
{
InitializeComponent();
Manager boss = new Manager();
string[] reports = boss.runWorkers(50);
}
}
}
namespace Workers
{
class Manager
{
public reports[] runWorkers(int numWorkers)
{
BackgroundWorker worker = new BackgroundWorker();
for (int i = 0; i < numWorkers; i++)
{
worker.DoWork += delegate(object s, DoWorkEventArgs args)
{
string report = this.job();
};
}
worker.RunWorkerAsync();
//Return reports here...
}
public string job()
{
Thread.Sleep(2000);
return "Job Completed";
}
}
}
You could try Task in .NET 4.0 System.Threading.Tasks
After you call StartNew main thread continues in parallel doing whatever you want it to do, then once it reaches a point where return value is required in Main Thread, main thread is blocked till the Result is returned by the method called on the other thread. If the result is already returned by the main thread reaches the WriteLine there is no blocking.
Task task = Task.Factory.StartNew(SomeMethod);
Console.WriteLine(task.Result);
public static string SomeMethod()
{
return "Hello World";
}
OR
Task task = Task.Factory.StartNew(() => { return "Hello World"; } );
Console.WriteLine(task.Result);
Check this blog for more interesting samples.
EDIT
After below (rather frustrating) discussion I had to make an edit to this answer to justify a right answer.
in the .NET Framework 4, tasks are the preferred API for writing multi-threaded, asynchronous, and parallel code. Check MSDN
Your best bet is to let the whole thing run asynchronously. If you don't let runWorkers return until all the workers are done, then you're giving up the primary benefit of asynchronous operations, which is that you can do other things (like respond to other events) while they're running.
A few suggestions toward that end:
Create an ObservableCollection to hold the reports. With observable collections, you can bind UI elements to it and they will automatically update as the collection changes. It is also possible to programmatically capture the collection's CollectionChanged event if you need to know when it changes. A word of caution, though - never modify this collection from inside the DoWork procedure!
You will need to create a different BackgroundWorker for each report. If you try to run a BackgroundWorker that's already working, you'll get an exception. However, be aware that starting a very large number of BackgroundWorkers simultaneously might cause the system to thrash a bit. In those cases you might want to look into using ThreadPool instead.
Attach a RunWorkerCompleted event handler to each BackgroundWorker. This event handler should unpack the results of the RunWorkerCompletedEventArgs's Result property, and add it to the collection. If the BackgroundWorker was started on the main thread, then this event is guaranteed to be raised on the main thread, so it should be safe to update the collection from this event handler.
Here's a rough sketch of how you might do it:
class Manager
{
public ObservableCollection<string> Reports { get; private set; }
public void runWorkers(int numWorkers)
{
for (int i = 0; i < numWorkers; i++)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.RunWorkerAsync(i);
}
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = Job((int)e.Argument);
}
public void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if(e.Error != null)
{
// handle error
}
else
{
Reports.Add(e.Result as string);
}
}
private string Job(int jobID)
{
Thread.Sleep(2000);
return string.Format("Job {0} Completed", jobID);
}
}
I'm currently writing a little GUI program that does some work and exits afterwards. While work is done, the GUI thread is updated with infos for the user.
This is the pattern I'm currently using and I'm thinking it's not the most elegant one:
static void MainForm_Loaded(BeoExport exporter)
{
// Thread 1 runs the Export
workerThread = new Thread(() =>
{
exporter.StartExport();
// don't exit immediately, so the user sees someting if the work is done fast
Thread.Sleep(1000);
});
// Thread 2 waits for Thread 1 and exits the program afterwards
waiterThread = new Thread(() =>
{
workerThread.Join();
Application.Exit();
});
workerThread.Start();
waiterThread.Start();
}
So what pattern/mechanics would you use to do the same?
To clarify: I was not interested in a way to update the GUI thread. That's already done. This might sound esoteric but I was lookig for the right way to quit the application.
If I could, I would give Dave the credits, since he pointed out the usefulness of the BackgroundWorker.
Have you considered a BackgroundWorker thread instead? You can use its ReportProgress method and ProgressChanged event to update the GUI (with a progress bar perhaps), assuming that you can refactor BeoExport.StartExport method to also report progress. This gives the users visible feedback that work is actually happening.
I don't understand why do you use two threads. You can use threadpool:
ThreadPool.QueueUserWorkItem((state)=>{
exporter.StartExport();
Thread.Sleep(1000);
Application.Exit();
});
I suggest you to use the BackgroundWorker class. It's thought to do the kind of job you're doing. You could do domething like this:
public class Form1 : Form
{
private BackgroundWorker worker;
private ProgressBar bar;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
bar= new ProgressBar();
bar.Dock = DockStyle.Top;
Controls.Add(bar);
worker = new BackgroundWorker();
worker.WorkerReportsProgress=true;
worker.RunWorkerCompleted += delegate
{
Close();
};
worker.ProgressChanged += delegate(object sender, ProgressChangedEventArgs ev)
{
bar.Value = ev.ProgressPercentage;
};
worker.DoWork += worker_DoWork;
worker.RunWorkerAsync();
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
//do your work here. For the example, just sleep a bit
//and report progress
for (var i = 0; i < 100;i++ )
{
Thread.Sleep(50);
worker.ReportProgress(i);
}
}
}
You can use an AutoResetEvent. The main thread waits for the autoreset event to be reset.
var wh = new AutoResetEvent(false);
var workerThread = new Thread(() =>
{
exporter.StartExport();
// don't exit immediately, so the user sees something if the work is done fast
Thread.Sleep(5000);
wh.Set();
});
workerThread.Start();
wh.WaitOne();
Application.Current.Shutdown();
Have you taken a look at the Task Parallel Library in .net 4 you can set up a task and the library will work out to best pararellise it for you, either threading, working a seperate CPU core's the is a load of great information about it online.
Regards
Iain
To add a little to Lain's answer, here's a Console sample using a Task from the System.Threading.Tasks namespace.
class Program
{
static void Main(string[] args)
{
Task<int> task = Task<int>.Factory.StartNew(() =>
{
Exporter exporter = new Exporter();
int i = exporter.StartExport();
return i;
});
int iResult = task.Result;
Console.WriteLine(iResult);
Console.ReadLine();
}
class Exporter {
public int StartExport()
{
//simulate some work
System.Threading.Thread.Sleep(500);
return 5;
}
}
}
Using a BackgroundWorker might help you implement your background processing. If you wanted to stick with your current pattern then consider the following.
static void MainForm_Loaded(BeoExport exporter)
{
workerThread = new Thread(() =>
{
exporter.StartExport();
Thread.Sleep(1000);
MainForm.BeginInvoke(
(Action)(() =>
{
MainForm.Close();
});
});
workerThread.IsBackground = true;
workerThread.Start();
}
Have the worker thread send a notification message of some description to the main thread. The GUI can then either exit or display a "done" message as appropriate.