I'm developing Xamarin.Mac(Cocoa) using C#. I want to develop application waiting seconds sometimes, so I developed waiting function using Task.Delay.
But repeating Task.Delay causes a large delay.
This is a test code for Cocoa.
using System; using System.Threading.Tasks; using System.Threading; using AppKit; using Foundation; namespace TaskDelayTest { public partial class ViewController : NSViewController { public ViewController(IntPtr handle) : base(handle) { } public override void ViewDidLoad() { base.ViewDidLoad(); } public override NSObject RepresentedObject { get { return base.RepresentedObject; } set { base.RepresentedObject = value; } } async partial void Execute(AppKit.NSButton sender) { while (true) { int millisecond = 1000; Console.WriteLine($"WaitTime : {millisecond}"); var startDate = DateTime.Now; await Task.Delay(millisecond).ConfigureAwait(false); var endDate = DateTime.Now; var diff = (endDate - startDate); Console.WriteLine($"WaitEnd : {endDate.ToString("yyyy/MM/dd HH:mm:ss.fff")}"); Console.WriteLine($"DiffTime : {diff.TotalMilliseconds}"); } } } }
Console result:
.
.
.
(Repeating a lot of times)
.
.
.
WaitTime : 1000 WaitEnd : 2018/02/01 01:00:25.784 DiffTime : 1000.192
WaitTime : 1000 WaitEnd : 2018/02/01 01:00:26.784 DiffTime : 1000.193
WaitTime : 1000 WaitEnd : 2018/02/01 01:00:27.785 DiffTime : 1000.232
WaitTime : 1000 WaitEnd : 2018/02/01 01:00:28.785 DiffTime : 1000.462
WaitTime : 1000 WaitEnd : 2018/02/01 01:00:39.785 DiffTime : 10999.643
WaitTime : 1000 WaitEnd : 2018/02/01 01:00:42.259 DiffTime : 2473.116
WaitTime : 1000 WaitEnd : 2018/02/01 01:00:43.582 DiffTime : 1322.505
WaitTime : 1000 WaitEnd : 2018/02/01 01:00:44.582 DiffTime : 1000.173
WaitTime : 1000 WaitEnd : 2018/02/01 01:00:45.582 DiffTime : 1000.147
WaitTime : 1000 WaitEnd : 2018/02/01 01:00:48.973 DiffTime : 3389.941
WaitTime : 1000 WaitEnd : 2018/02/01 01:00:49.973 DiffTime : 1000.186
WaitTime : 1000 WaitEnd : 2018/02/01 01:00:50.973 DiffTime : 1000.186
WaitTime : 1000 WaitEnd : 2018/02/01 01:00:52.083 DiffTime : 1108.889
.
.
.
Sometimes very very delayed. This did not happen on Windows. It only occurred with Xamarin.Mac.
And I have to develop as asynchronous function because it's cocoa application. If I develop as not async function, it locks UI.
Answers
So waking up significantly after your scheduled wake up time is not unexpected when writing code of that nature.
Task.Delay(millisecond)
is saying "wait at least X ms", not "wake up me at this time".You may want to read this documentation: https://developer.xamarin.com/guides/ios/application_fundamentals/threading/
But to answer the root question, you need to integrate more closely with the underlying OS. NSTimer doen't have real-time guarantees, and can shift your wake up times when your device is on batteries, but will likely get you roughly what you want:
Since Task.Delay gets scheduled on the thread pool, it has higher jitter if you need that sort of precision.
Hi, I encounter the same problem, when I repeat Task.Delay(100) or jus Thread.Sleep(100) in an just empty Xamarin.Mac app, it will delay even up tp 10s. Have you solved it yet?
I also tried > @ChrisHamons 's solution by using NSTimer instead, but the same:
delay time: 98
delay time: 100
delay time: 99
delay time: 99
delay time: 99
delay time: 99
delay time: 99
delay time: 99
delay time: 99
delay time: 10098
delay time: 6321
delay time: 4078
delay time: 1284
delay time: 2869
delay time: 1293
delay time: 1078
It seems if the Xamarin.Mac app screens off for a while, the Task.Delay() or NSTimer() will not working correctly, but if I click the app to make it show on the top of the screen, the timing will becomes correct again. How weird it is. Will cocoa app also enter a status like sleeping?
Sorry for reposting so often, but I think I already figured out what the issue is. MacOS will enable 'App Nap' automatically, so if the app is not on the topmost foreground, it will take a nap eventually and the timer will become unpredictable, that is the reason why Task.Delay() or other timing functions do not work. There is an API can control this behaviour.
https://stackoverflow.com/questions/33558194/disable-app-nap-for-mono-mac-application
The accepted answer works like a charm.
Not sure whether yours is due to the same issue, hope it will be helpful for anyone who suffer from this problem.