Reputation:
The method below is suppose to run for the (duration is milliseconds) being passed in for case 0:, but what I'm seeing is the method may take up to 2 seconds to run for a 400ms duration. Is it possible that Task.run is taking long time to start? If so is there a better way?
private static async void PulseWait(int duration, int axis){
await Task.Run(() =>
{
try
{
var logaction = true;
switch (axis)
{
case 0:
var sw1 = Stopwatch.StartNew();
if (duration > 0) duration += 20; // allowance for the call to the mount
while (sw1.Elapsed.TotalMilliseconds <= duration) { } // wait out the duration
_isPulseGuidingRa = false;
logaction = false;
break;
case 1:
var axis2Stopped = false;
var loopcount = 0;
switch (SkySettings.Mount)
{
case MountType.Simulator:
while (!axis2Stopped && loopcount < 30)
{
loopcount++;
var statusy = new CmdAxisStatus(MountQueue.NewId, Axis.Axis2);
var axis2Status = (AxisStatus)MountQueue.GetCommandResult(statusy).Result;
axis2Stopped = axis2Status.Stopped;
if (!axis2Stopped) Thread.Sleep(10);
}
break;
case MountType.SkyWatcher:
while (!axis2Stopped && loopcount < 30)
{
loopcount++;
var statusy = new SkyIsAxisFullStop(SkyQueue.NewId, AxisId.Axis2);
axis2Stopped = Convert.ToBoolean(SkyQueue.GetCommandResult(statusy).Result);
if (!axis2Stopped) Thread.Sleep(10);
}
break;
default:
throw new ArgumentOutOfRangeException();
}
_isPulseGuidingDec = false;
logaction = false;
break;
}
var monitorItem = new MonitorEntry
{ Datetime = HiResDateTime.UtcNow, Device = MonitorDevice.Telescope, Category = MonitorCategory.Mount, Type = MonitorType.Data, Method = MethodBase.GetCurrentMethod().Name, Thread = Thread.CurrentThread.ManagedThreadId, Message = $"PulseGuide={logaction}" };
MonitorLog.LogToMonitor(monitorItem);
}
catch (Exception)
{
_isPulseGuidingDec = false;
_isPulseGuidingRa = false;
}
});}
Log showing how time taken... 33652,2019:07:12:01:15:35.590,13,AxisPulse,Axis1,0.00208903710815278,400,0,True <<--line just before PulseWait is called with 400ms duration 33653,2019:07:12:01:15:35.591,13,SendRequest,:I1250100 33654,2019:07:12:01:15:35.610,13,ReceiveResponse,:I1250100,= 33655,2019:07:12:01:15:36.026,13,SendRequest,:I1B70100 33656,2019:07:12:01:15:36.067,13,ReceiveResponse,:I1B70100,= 33657,2019:07:12:01:15:36.067,13,SendRequest,:j1 33658,2019:07:12:01:15:36.120,13,ReceiveResponse,:j1,=DDCDBD 33659,2019:07:12:01:15:36.120,13,SendRequest,:j2 33660,2019:07:12:01:15:36.165,13,ReceiveResponse,:j2,=67CF8A 33661,2019:07:12:01:15:36.467,13,SendRequest,:j1 33662,2019:07:12:01:15:36.484,13,ReceiveResponse,:j1,=10CEBD 33663,2019:07:12:01:15:36.484,13,SendRequest,:j2 33664,2019:07:12:01:15:36.501,13,ReceiveResponse,:j2,=67CF8A 33665,2019:07:12:01:15:36.808,13,SendRequest,:j1 33666,2019:07:12:01:15:36.842,13,ReceiveResponse,:j1,=3CCEBD 33667,2019:07:12:01:15:36.842,13,SendRequest,:j2 33668,2019:07:12:01:15:36.868,13,ReceiveResponse,:j2,=67CF8A 33669,2019:07:12:01:15:37.170,13,SendRequest,:j1 33670,2019:07:12:01:15:37.188,13,ReceiveResponse,:j1,=6BCEBD 33671,2019:07:12:01:15:37.188,13,SendRequest,:j2 33672,2019:07:12:01:15:37.204,13,ReceiveResponse,:j2,=67CF8A 33673,2019:07:12:01:15:37.221,5,b__0,PulseGuide=False <<--PulseWait is finished 1.631ms after start
Upvotes: 2
Views: 1349
Reputation: 41018
The purpose of async
and await
is to make things easy. But just like everything that makes things easy, it comes with a cost of having full control over what's going on. Here, it's really a cost of asynchronous programming in general. The point of asynchronous programming is to free up the current thread so that the current thread can go off and do something else. But if something else is done on the current thread, then the continuation of what you were doing must wait until that is done. (i.e. What comes after the await
may not happen instantaneously after the task completes)
So while asynchronous programming will help overall performance (like increasing the overall throughput performance of a web app), but will actually hurt the performance of any one specific task. If every millisecond counts to you, you might be able to do the low-level tasks yourself, like creating a Thread (if this really needs to be run on a separate thread).
Here is a simple example that demonstrates this:
var s = new Stopwatch();
// Test the time it takes to run an empty method on a
// different thread with Task.Run and await it.
s.Start();
await Task.Run(() => { });
s.Stop();
Console.WriteLine($"Time of Task.Run: {s.ElapsedMilliseconds}ms");
// Test the time it takes to create a new thread directly
// and wait for it.
s.Restart();
var t = new Thread(() => { });
t.Start();
t.Join();
s.Stop();
Console.WriteLine($"Time of new Thread: {s.ElapsedMilliseconds}ms");
The output will vary, but it looks something like this:
Time of Task.Run: 8ms
Time of new Thread: 0ms
In an application with lots of other things going on, that 8ms could be much more if some other operation uses the thread during the await
.
That's not to say that you should use Thread
. t.Join()
is not an asynchronous operation. It will block the thread. So if PulseWait
runs on the UI thread (if this is a UI app), it will lock the UI thread, which is a bad user experience. In that case, you may not be able to get around the cost of using asynchronous code.
If this is not an application with a UI, then I don't see why you need to do all that on a different thread at all. Maybe you can just.... not do that.
Upvotes: 3