What's the Difference Between Synchronous and Asynchronous Calls in Objective-C, Versus Multi-Threading

What's the difference between synchronous and asynchronous calls in Objective-C, versus multi-threading?

When you invoke something synchronously, it means that the thread that initiated that operation will wait for the task to finish before continuing. Asynchronous means that it will not wait.

Having said that, when people suggest that you perform some slow or expensive process asynchronously, they are implicitly suggesting not only that you should run it asynchronously, but that you should do that on a background thread. The goal is to free the main thread so that it can continue to respond to the user interface (rather than freezing), so you are dispatching tasks to a background thread asynchronously.

So, there are two parts to that. First, using GCD as an example, you grab a background queue (either grab one of the global background queues, or create your own):

// one of the global concurrent background queues

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

// or you could create your own serial background queue:
//
// dispatch_queue_t queue = dispatch_queue_create("com.domain.app.queuename", 0);

Second, you dispatch your tasks to that queue asynchronously:

dispatch_async(queue, ^{
// the slow stuff to be done in the background
});

The pattern for operation queues is very similar. Create an operation queue and add operations to that queue.

In reality, the synchronous vs asynchronous distinction is completely different from the main queue vs background queue distinction. But when people talk about "run some slow process asynchronously", they're really saying "run some slow process asynchronously on a background queue."

What is the difference between asynchronous programming and multithreading?

Your misunderstanding is extremely common. Many people are taught that multithreading and asynchrony are the same thing, but they are not.

An analogy usually helps. You are cooking in a restaurant. An order comes in for eggs and toast.

  • Synchronous: you cook the eggs, then you cook the toast.
  • Asynchronous, single threaded: you start the eggs cooking and set a timer. You start the toast cooking, and set a timer. While they are both cooking, you clean the kitchen. When the timers go off you take the eggs off the heat and the toast out of the toaster and serve them.
  • Asynchronous, multithreaded: you hire two more cooks, one to cook eggs and one to cook toast. Now you have the problem of coordinating the cooks so that they do not conflict with each other in the kitchen when sharing resources. And you have to pay them.

Now does it make sense that multithreading is only one kind of asynchrony? Threading is about workers; asynchrony is about tasks. In multithreaded workflows you assign tasks to workers. In asynchronous single-threaded workflows you have a graph of tasks where some tasks depend on the results of others; as each task completes it invokes the code that schedules the next task that can run, given the results of the just-completed task. But you (hopefully) only need one worker to perform all the tasks, not one worker per task.

It will help to realize that many tasks are not processor-bound. For processor-bound tasks it makes sense to hire as many workers (threads) as there are processors, assign one task to each worker, assign one processor to each worker, and have each processor do the job of nothing else but computing the result as quickly as possible. But for tasks that are not waiting on a processor, you don't need to assign a worker at all. You just wait for the message to arrive that the result is available and do something else while you're waiting. When that message arrives then you can schedule the continuation of the completed task as the next thing on your to-do list to check off.

So let's look at Jon's example in more detail. What happens?

  • Someone invokes DisplayWebSiteLength. Who? We don't care.
  • It sets a label, creates a client, and asks the client to fetch something. The client returns an object representing the task of fetching something. That task is in progress.
  • Is it in progress on another thread? Probably not. Read Stephen's article on why there is no thread.
  • Now we await the task. What happens? We check to see if the task has completed between the time we created it and we awaited it. If yes, then we fetch the result and keep running. Let's suppose it has not completed. We sign up the remainder of this method as the continuation of that task and return.
  • Now control has returned to the caller. What does it do? Whatever it wants.
  • Now suppose the task completes. How did it do that? Maybe it was running on another thread, or maybe the caller that we just returned to allowed it to run to completion on the current thread. Regardless, we now have a completed task.
  • The completed task asks the correct thread -- again, likely the only thread -- to run the continuation of the task.
  • Control passes immediately back into the method we just left at the point of the await. Now there is a result available so we can assign text and run the rest of the method.

It's just like in my analogy. Someone asks you for a document. You send away in the mail for the document, and keep on doing other work. When it arrives in the mail you are signalled, and when you feel like it, you do the rest of the workflow -- open the envelope, pay the delivery fees, whatever. You don't need to hire another worker to do all that for you.

Asynchronous vs Multithreading - Is there a difference?

This question is darn near too general to answer.

In the general case, an asynchronous call does not necessarily create a new thread. That's one way to implement it, with a pre-existing thread pool or external process being other ways. It depends heavily on language, object model (if any), and run time environment.

Asynchronous just means the calling thread doesn't sit and wait for the response, nor does the asynchronous activity happen in the calling thread.

Beyond that, you're going to need to get more specific.

Synchronous Vs Asynchronous on iPhone

You should always use asynchronous loading of network requests. Never block the main thread waiting for a network response.

Asynchronous can be either synchronous on a separate thread, or scheduled in the run loop of any thread.

Hope this helps!

what is diff b/w Synchronous and asynchronous requests ,How check this operations programmatically

In answer to your question, synchronous requests block the thread from which they were called until the request finishes. (And for this reason, synchronous requests are generally discouraged.) Asynchronous requests let the current thread continue execution (e.g. continue to respond to user interaction with the app; respond to system events; etc.) while the request is being performed. This generally preferable.

Your code was performing asynchronous request (which is good). There were some issues, though:

  1. You shouldn't use NSURLConnection anymore. It's deprecated. Use NSURLSession. It's actually simpler, as you generally don't have to write those delegate methods (unless you want to because you have some compelling need to do so).

    For more information on NSURLSession, see the Using NSURLSession in the URL Session Programming Guide. Or see WWDC 2013 video What's New in Foundation Networking for a nice introduction.

  2. You aren't doing some error handling. You're checking for fundamental errors (e.g. no network), which is very good, but you weren't considering other web server errors which may not always result in a NSError object, but may simply result in a HTTP status code other than 200. I'd suggest checking for that.

    See section 10 of RFC 2616 for a list of HTTP status codes.

  3. You are setting a Content-Type of application/json. But this isn't a JSON request. (Sure, the response is JSON, but the request isn't.) Often you'd use application/x-www-form-urlencoded for requests like this.

  4. In your code snippet, you suggested that the response from the server was JSON with a NSArray as the top level object. But the top level object is a NSDictionary.

  5. You are using JSONValue. I'm not sure which JSON library that is, but many of us just use the built-in NSJSONSerialization class that Apple provides. A long time ago, before Apple provided NSJSONSerialization, we'd use third-party libraries for parsing JSON, but that's no longer needed.

The correct way to send a request with NSURLSession is as follows:

NSURL *url = [NSURL URLWithString:@"http://api.kivaws.org/v1/loans/search.json?status=fundraising"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

[request setHTTPMethod:@"GET"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error != nil) {
NSLog(@"fundamental network error = %@", error);
return;
}

if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
if (statusCode != 200) {
NSLog(@"Warning; server should respond with 200 status code, but returned %ld", (long)statusCode);
}
}

NSError *parseError;
NSDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
if (responseObject) {
NSLog(@"responseObject = %@", responseObject);
} else {
NSLog(@"Error parsing JSON: %@", parseError);
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"responseString = %@", responseString);
}
}];
[task resume];

// Note, you'll reach this portion of your code before the
// above `completionHandler` runs because this request runs
// asynchronously. So put code that uses the network response
// above, inside that `completionHandler`, not here.

what is the difference between sync and async input source for run loops?

The Threading Programming Guide: Run Loops says:

A run loop receives events from two different types of sources. Input sources deliver asynchronous events, usually messages from another thread or from a different application. Timer sources deliver synchronous events, occurring at a scheduled time or repeating interval. Both types of source use an application-specific handler routine to process the event when it arrives.

But a timer only blocks the thread while the timer’s closure or selector method is running. But as soon as you return from that, the thread is no longer blocked. So make sure to get in and out as quickly as possible.

For example, if you have scheduled a timer to fire in 10 seconds, and the code in the timer’s handling closure/selector takes 100 msec to run, then the thread is not blocked until the timer fires, and then only for 100 msec. Same with repeating timers.

Bottom line, as long as you’re not doing anything too computationally expensive in your timer handler, there’s nothing to worry about. And if you do need to do anything that might block for any material amount of time, then either have your timer handler asynchronously dispatch that relevant code to some background queue, or just schedule a GCD timer to run on a background queue directly, bypassing Timer altogether.

But for most Timer use-cases, this just isn’t an issue.

Trying To Understand the Difference Between Synchronous and Asynchronous Network Calls

You can use .data(for: URLRequest) in order to add headers.

    func fetchTrendingMoviesAsynchronous() async {
guard let url = URL(string: "https://api.trakt.tv/movies/trending") else {
print("Could not get trending movies.")
return
}
var request = URLRequest(url: url)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("2", forHTTPHeaderField: "trakt-api-version")
request.addValue("My_API_Key", forHTTPHeaderField: "trakt-api-key")
do {
let (data, _) = try await URLSession.shared.data(for: request)
if let decodedResponse = try? JSONDecoder().decode([TrendingMovie].self, from: data) {
print("We got the trending movies.")
trendingMovies = decodedResponse
}
}catch {
print("Could not get trending movies.")
}
}

Asynchronous vs synchronous execution, what is the main difference?

When you execute something synchronously, you wait for it to finish before moving on to another task. When you execute something asynchronously, you can move on to another task before it finishes.

That being said, in the context of computers this translates into executing a process or task on another "thread." A thread is a series of commands (a block of code) that exists as a unit of work. The operating system can manage multiple threads and assign a thread a piece ("slice") of processor time before switching to another thread to give it a turn to do some work. At its core (pardon the pun), a processor can simply execute a command, it has no concept of doing two things at one time. The operating system simulates this by allocating slices of time to different threads.

Now, if you introduce multiple cores/processors into the mix, then things CAN actually happen at the same time. The operating system can allocate time to one thread on the first processor, then allocate the same block of time to another thread on a different processor. All of this is about allowing the operating system to manage the completion of your task while you can go on in your code and do other things.

Asynchronous programming is a complicated topic because of the semantics of how things tie together when you can do them at the same time. There are numerous articles and books on the subject; have a look!



Related Topics



Leave a reply



Submit