I am familiar with await-async conception, but I am writing a lot of linear code that should always run in single thread and synchronously. Also it's much easier to debug synchronously code.
Is it possible to make ALL code work synchronously? Regardless of async\await calls in code?
Related
In my daily work, I can handle some multi-thread condition using GCD, but I also see the usage of thread in project, example, log module use thread but queue in my project. I just can't understand why. There is some benefit to use thread than GCD? How should I choose?
pthread is often used by cross-platform code, so you are quite likely to run into it when you include third-party libraries in your code, and usually don't touch it.
Using NSThread would be very, very, very rare. Except for calling [NSThread isMainThread] to determine whether your code is running on the main thread or on a background thread. Unless you have a real good reason to do otherwise, use GCD. Mostly because it is so much easier to use that suddenly you will use multithreading in places where you would never have used it otherwise.
Why is it the responsibility of the programmer to call UI related methods on the main thread with:
DispatchQueue.main.async {}
Theoretically, couldn’t this be left up to the compiler or some other agent to determine?
The actual answer is developer inertia and grandfathering.
The Cocoa UI API is huge—nay, gigantic. It has also been in continuous development since the 1990's.
Back when I was a youth and there were no multi-core, 64-bit, anything, 99.999% of all applications ran on the main thread. Period. (The original Mac OS, pre-OS X, didn't even have threads.)
Later, a few specialized tasks could be run on background threads, but largely apps still ran on the main thread.
Fast forward to today where it's trivial to dispatch thousands of tasks for background execution and CPUs can run 30 or more current threads, it's easy to say "hey, why doesn't the compiler/API/OS handle this main-thread thing for me?" But what's nigh on impossible is re-engineering four decades of Cocoa code and apps to make that work.
There are—I'm going to say—hundreds of millions of lines of code that all assume UI calls are executing concurrently on the main thread. As others have pointed out, there is no cleaver switch or pre-processor that's going to undo all of those assumptions, fix all of those potential deadlocks, etc.
(Heck, if the compiler could figure this kind of stuff out we wouldn't even have to write multi-threaded code; you'd just let the compiler slice up your code so it runs concurrently.)
Finally, such a change just isn't worth the effort. I do Cocoa development full time and the number of times I have to deal with the "update control from a background thread problem" occurs, at most, once a week or so. There's no development cost-benefit analysis that's going to dedicate a million man-hours to solving a problem that already has a straight forward solution.
Now if you were developing a new, modern, UI API from scratch, you'd simply make the entire UI framework thread safe and whole question goes away. And maybe Apple has a brand new, redesigned-from-the-ground-up, UI framework in a lab somewhere that does that. But that's the only way I see something like this happening.
You would be substituting one kind of frustration for another.
Suppose that all UI-related methods that require invocation on the main thread did so by:
using DispatchQueue.main.async: You would be hiding asynchronous behaviour, with no obvious way to "follow up" on the result. Code like this would now fail:
label.text = "new value"
assert(label.text == "new value")
You would have thought that the property text just harmlessly assigned some value. In fact, it enqueued a work item to asynchronously execute on the main thread. In doing so, you've broken the expectation that your system has reached its desired state by the time you've completed that line.
using DispatchQueue.main.sync: You would be hiding a potential for deadlock. Synchronous code on the main queue can be very dangerous, because it's easy to unintentionally block (on the main thread) yourself waiting for such work, causing deadlock.
I think one way this could have been achieved is by having a hidden thread dedicated to UI. All UI-related APIs would switch to that thread to do their work. Though I don't know how expensive that would be (each switch to that thread is probably no faster than waiting on a lock), and I could imagine there's lots of "fun" ways that'll get you to write deadlocking code.
Only on rare instances would the UI call anything in the main thread, except for user login timeouts for security. Most UI related methods for any particular window are called within the thread that was started when the window was initialized.
I would rather manage my UI calls instead of the compiler because as a developer, I want control and do not want to rely on third party 'black boxes'.
check https://developer.apple.com/documentation/code_diagnostics/main_thread_checker
and UPDATE UI FROM MAIN THREAD ONLY!!!
The app I am working on fetches a bunch of different newsfeeds when it first starts up and updates any expired ones. While this is happening the interface often freezes up and you can't click anything. The actual network calls are being done on a separate thread, but the database operations are being done on the main thread. Would this cause the interface to freeze?
I have been told that I need to make it to where only two feeds to update are inserted into the network operation queue at a time so that it won't try all of them at once, but it's already set up to only do so many network calls at once. I don't understand how having less things in a queue at a time would cause it to go faster if they're just going to be put in there sequentially anyways. Please correct me if I am wrong, I'm still pretty new to this.
Any kind of help regarding what could cause the UI to freeze up during startup like this would be much appreciated!
It is always a good idea to move time consuming operation away from the main thread.
Fortunately it is pretty simple to do on iOS. If the time-consuming task is fairly simple you could consider using performSelectorInBackground
e.g:
[self performSelectorInBackground:#selector(myFunction:)
withObject:myParam];
It is however important to remberber, that you must not access the GUI from the background thread. To get objects back to the main thread use performSelectorOnMainThread
e.g:
[self performSelectorOnMainThread:#selector(myFunction:) myParamwaitUntilDone:YES];
Try applying this strategy to your database calls. Depending on your scenario you might want to wrap it up in a NSOperation or use a Thread when the cause of the freeze is found.
I am confused on where to use which multithreading tool in iOS for hitting services and changing UI based on service data,
firstly I got accustomed to using NSURLConnection and its delegates, used didreceiveresponse, didreceivedata etc delegates to achieve the task
secondly I learned and used GCD to hit services and update the UI from within the block code
Now I am learning to use performSelectorInBackground() to do work in background thread
Clearly confused on which tool to use where?
NSURLConnection with delegate calls is "old school" way of receiving data from remote server. Also it's not really comfortable to use with few NSURLConnection instances in a single class (UIViewController or what not). Now it's better to use sendAsynchronousRequest.. method with completion handler. You can also define on which operation queue (main for UI, or other, background one) the completion handler will be run.
GCD is good for different tasks, not only fetching remote resources with initWithContentsOfURL: methods. You can also control what type of queues will receive your blocks (concurrent, serial ,etc.)
performSelectorInBackground: is also "old school" way of performing a method in background thread. If you weren't using ARC, you'd need to setup separate autorelease pool to avoid memory leaks. It also has a limitation of not allowing to accept arbitrary number of parameters to given selector. In this case it's recommended to use dispatch_async.
There are also NSOperationQueue with NSOperation and its subclasses (NSInvocationOperation & NSBlockOperation), where you can run tasks in the background as well as get notifications on main thread about finished tasks. IMHO They are more flexible than GCD in a way that you can create your own subclasses of operations as well as define dependencies between them.
The most important thing is, that you never change UI anyway in another thread except the main thread.
I think, that all points you mentioned use the same technique in the background: GDC. But I'm not sure of that.
Anyway it doesn't matter which tool you should use in terms of threading.
It's rather a question of your purpose. If you wan't to fetch an small image or just few data you can use contentsOfURLin a performSelectorInBackground() or a GDC dispatch block.
If it's about more data and more information like progress or error handling you should stick with *NSURLConnection`.
I suggest using GCD in all cases. Other techniques are still around but mainly for backward compatibility.
GCD is better for 3 reasons (at least):
It's extremely easy to use and the code remains very readable because of the use of blocks
It is lower level than things like NSOperation so it is much faster when you need high performance multi threading
It's lightweight and non-intrusive so your code doesn't have to change substantially when you want to add thread management in the middle of a method.
I am developing a WPF application with C# 4.0 where some user-specific code will
be compiled at runtime and then executed inside an AppDomain. The process might take 10 ms or 5 minutes. The AppDomain will be created by Task.Factory.StartNew(). Works fine.
Now I want to be able to cancel/interrupt the execution. I can press a
Stop button while the codes is executing but how can I cancel the Task? I know:
there is the CancellationToken.IsCancellationRequested property but I cannot
loop through something. This is why I cannot check the value while executing
the (atomic) code. And unloading the AppDomain does not stop the Task.
FYI: I took the Task class because it easy to use. If Thread would be useful: No problem.
Can someone help me? A short code snippet would be nice :).
Thank you.
Aborting a thread or a task is a code smell of a badly designed solution.
If that is your decision, you should consider that every line of code could be the last one to be executed and consider releasing any unmanaged resource, lock, etc that could leave the system in an inconsistent state. In theory we should always be this careful, but in practice this doesn't hold.
If you try with a Thread and the inviting .Abort() method, you should consider that ThreadAbortException is a special exception in terms of try-catch and finally blocks. Additionally, you can't even be sure that the thread is going to be aborted.
In regards of using a Task, AFAIK (I'm not an expert in TPL) I'm afraid you cannot do what you want. You should somehow re-design your logic to consider the cancellation token and cleanly stop your computation.