1. 程式人生 > >iOS 支援最大的併發數

iOS 支援最大的併發數

The problem

Did you know iOS has a limit on the number of concurrent NSURLConnections to the same end-point? No? Maybe you should, we discovered it the hard way.
Create a new single-view app project on Xcode and copy the following snippet inside the viewDidLoad event of your view controller:
- (void
)viewDidLoad { [superviewDidLoad]; // Do any additional setup after loading the view, typically from a nib. NSMutableArray *connections= [NSMutableArrayarray]; for (int i= 0; i < 4; i++) { NSURL *url= [NSURLURLWithString:@"http://push.lightstreamer.com/lightstreamer/create_session.txt?LS_user=&LS_adapter_set=DEMO&LS_ios_version=1.0"];
NSURLRequest *req= [NSURLRequestrequestWithURL:url]; NSURLConnection *conn= [[NSURLConnectionallocinitWithRequest:req delegate:selfstartImmediately:NO]; [connections addObject:conn]; } for (NSURLConnection *conn in connections) [conn start]; }
Then add some simple NSURLConnection delegate event handlers: 


- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { NSLog(@"Connection %p did receive response %d", connection, [(NSHTTPURLResponse *) response statusCode]); } - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { NSLog(@"Connection %p did receive %d bytes:\n%@", connection, [data length], [[[NSStringallocinitWithData:data encoding:NSUTF8StringEncodingautorelease]); } - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { NSLog(@"Connection %p did fail with error %@", connection, error); } So, what does this code do? It will open 4 simultaneous stream sessions to Lightstreamer's demo server. There's nothing secret with this code: if you read Lightstreamer's Network Protocol Tutorial you can see the URL request is compliant with the documentation. Except for that little "LS_ios_version" argument, which is needed to overcome NSURLConnection buffering. Run it and you will see 4 concurrent connections gracefully opening and then receiving Lightstreamer's keepalive message ("PROBE") once every 5 seconds. Everything looks fine. Now try to set the number of connections (in the for loop) to 5 or more, and you will have a surprise. From the fifth connection on, nothing will happen. The connection won't open, and if you wait long enough you will get something like this: 2013-01-07 17:03:27.828 LSConcurrencyTest3[31820:c07] Connection 0x715dd60 did fail with error Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo=0xe03ea70 {NSErrorFailingURLStringKey=http://push.lightstreamer.com/lightstreamer/create_session.txt?LS_user=&LS_adapter_set=DEMO&LS_ios_version=1.0, NSErrorFailingURLKey=http://push.lightstreamer.com/lightstreamer/create_session.txt?LS_user=&LS_adapter_set=DEMO&LS_ios_version=1.0, NSLocalizedDescription=The request timed out., NSUnderlyingError=0x716d390 "The request timed out."} Time out. Maybe you could think it's Lightstreamer's demo server which is limiting the number of concurrent connections. It's a reasonable doubt, so let's use something else. Let's try with the download of Apple's OS X 10.8.2 Combo Update, which is big enough (more on this later) to exhibit the same problem. Change the URL is this way: NSURL *url= [NSURL URLWithString:@"http://support.apple.com/downloads/DL1581/en_US/OSXUpdCombo10.8.2.dmg"]; Before running, comment the connection:didReceiveData: delegate event handler or you console will be flooded. Now run it and you will see the same problem: 4 connections will connect and start, from the fifth on they will be frozen. And after a while a time out will appear. The problem is evident with long running connections. Of course if your connections complete their purpose in a second or two you could never notice. But any long running connection exhibits this problem. And note that it happens both on the simulator and on any iOS device.

Possible explanation

First of all, why does this happen? We don't know for sure, but the most reasonable explanation is that the system is applying a limit that is suggested (but not mandated) in the HTTP protocol specification itself. See here: In our case, the problem pertains to streaming connections, which are typically open once the app starts and closed when the app terminates. A client may legitimately ask for more than 4 streaming connections to the same server. The underlying network connection details are completely hidden to Lightstreamer's client library users. They may simply not know that one more connection will be frozen while all the previous ones will run without a hitch. Moreover, the connection that is going to be frozen will end up in a time out error indistinguishable from a real network time out. You will have the perception your network is broken, when it is actually working perfectly. This may make it quite hard to track down the reason. 
The problem can't be solved directly, this limit is hard-coded in iOS. The only way to overcome the limit is to use different host names for the same end-point, i.e.: making the system think they are different end-points. Clearly, most of the times this is outside the reach of client-side developers. So, if you can't overcome the limit, at least try to live with it. Is there a way you can control how many connections are open toward the same end-point?

Solution

To solve the problem we developed our own thread pool implementation, featuring a configurable number of threads that will never be exceeded. It also features an unbound queue containing the operations it is going to to execute. Each time a thread completes an operation, it fetches the next from the queue. Once a thread has no more operations to execute, it is scheduled for disposal, and a timed collector will dispose of it soon after. Add a new operation and the thread will be reused, or a new one will be created. Based on this generic thread pool, we created a structure called URL dispatcher, which uses thread pools to run URL connections, keeping always under control the connection limit mentioned before. Actually, the URL dispatcher keeps a separate thread pool for each end-point, and runs the URL connection requests with it. Since the number of threads is limited, the number of concurrent connection is too. The URL dispatcher applies some heuristics on URL connection requests:
  • first of all, it makes a distinction between long running requests and short running requests;
  • it always keeps some spare threads available for short running requests (typically 1 out of 4), which in our case are usually control connections (subscription, messages, and so on);
  • when a long running connection is requested it is able to tell in advance if it will succeed or not (based on the current size of the thread pool of its end-point);
  • if a long running connection can't succeed because the limit has been reached, the requesting client can gracefully handle the condition;
  • finally, the Lightstreamer client uses this knowledge to notify the user and decide what to do: ignore the condition (the connection is going to be frozen), abort the connection or automatically switch to a polled connection (which uses short running requests); specific APIs to configure this behavior have been added. 
Thread pools and the URL dispatcher have been introduced with iOS client library version 1.2, and distributed with Lightstreamer server version 5.1. The StockList demo app, available on the App Store, already makes use of it. If you haven't upgraded to Lightstreamer 5.1 yet, this little piece of technology is worth the effort.

Update

The thread pool library has been released as open source and can be found on Lightstreamer's GitHub repository

Update #2

The article has been updated to reflect changed conditions in iOS 7: the maximum number of connections per end-point seems to have been decreased to 4, from 5 in iOS 6. Moreover, the original article claimed that iOS operation queues do not strictly enforce the maximum number of concurrent operations. This behavior is no more reproducible under iOS 7, so this claim has been removed. Note that good reasons to write your own thread pool implementation still exist. One for all: controlling when threads may be disposed of, enabling customized thread reuse.

相關推薦

iOS 支援併發

The problem Did you know iOS has a limit on the number of concurrent NSURLConnections to the same end-point? No? Maybe you should, we discovered it the

iOS GCD中如何控制併發

//聯絡人:石虎  QQ: 1224614774暱稱:嗡嘛呢叭咪哄 一、概述 1、GCD併發的困擾 在GCD中有兩種佇列,分別是序列佇列和併發佇列。在序列佇列中,同一時間只有一個任務在執行,不能充分利用多核 CPU 的資源,效率較低。 併發佇列可以分配多

mysql 檢視連線,狀態,併發

show status like '%max_connections%'; ##mysql最大連線數set global max_connections=1000 ##重新設定show variables like '%max_connections%'; ##查詢資料庫當前設定的最大連線數 show gl

瀏覽器同域名請求的併發限制

當我們在瀏覽網頁的時候,對瀏覽速度有一個重要的影響因素,就是瀏覽器的併發數量。併發數量簡單通俗的講就是,當瀏覽器網頁的時候同時工作的進行數量。   如果同時只有2個併發連線數數量,那網頁開啟的時候只能依賴於

(CSDN遷移) JAVA多執行緒實現-可控併發執行緒池(newFixedThreadPool)

上篇文章中介紹了單執行緒化執行緒池newSingleThreadExecutor,可控最大併發數執行緒池(newFixedThreadPool)與其最大的區別是可以通知執行多個執行緒,可以簡單的將newSingleThreadExecutor理解為newFixedThreadPool(1)。例如執行一下兩個程

Mysql 檢視連線,狀態 併發

-- show variables like '%max_connections%'; 檢視最大連線數 set global max_connections=1000 重新設定 mysql> show status like 'Threads%'; +---

Mysql 檢視連線,狀態 併發 && 怎麼設定才合理

show status like '%max_connections%'; ##mysql最大連線數 set global max_connections=1000 ##重新設定 show variables like '%max_connections%'; ##查詢資料庫當前設定的最大連線數 show

Mysql 檢視連線,狀態 併發(贊)

1.show status    Threads_connected  當前的連線數    Connections  試圖連線到(不管是否成功)MySQL伺服器的連線數。    Max_used_connections  伺服器啟動後已經同時使用的連線的最大數量。 2.set GLOBAL max_con

2018年最後一天 VsCode中執行nodeJs程式碼的簡單方法 Pgsql和Mysql的對比 Tomcat的併發 Spring AOP不起作用原因

發現2017的隨筆總結依舊適用,想堅持每天寫點東西分享,但感覺每天能原創分享的內容真的不多,尤其是要把自己想分享的內容寫清楚也需要額外花費很多的時間,這讓本來平時就工作比較忙的自己疲於應付,於是乎就轉載自己看到的一些好的文章分享,甚至有些文章自己都沒完全看完就發,湊合著完成了任務,但自己的成就感很低。因此我不

Tomcat的效能與併發

當一個程序有 500 個執行緒在跑的話,那效能已經是很低很低了。Tomcat 預設配置的最大請求數是 150,也就是說同時支援 150 個併發,當然了,也可以將其改大。當某個應用擁有 250 個以上併發的時候,應考慮應用伺服器的叢集。具體能承載多少併發,需要看硬體的配置,C

使用Filter限制J2EE併發

在開發J2EE的過程往往需要限制併發請求量從而減少伺服器異常的可能性。而這些通常都是通過叢集手段或外部代理來實現的。本文主要介紹單個應用如何不依賴其他程式來解決這個問題。 J2EE的每個請求都是經由過濾器(責任鏈模式),Servlet來執行的,每個請求的進入都需要過濾器的准

oracle 併發 會話查詢

SQL> select count(*) from v$session #當前的連線數 SQL> Select count(*) from v$session where status='ACTIVE' #併發連線數 SQL> select value

iOS GCD併發控制

dispatch_semaphore_t sem = dispatch_semaphore_create(1); dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); 這兩句程式碼為什麼會閃退 最後訊號數量不對等, d

Apache 設定併發

prefork的工作原理是, 控制程序在最初建立“StartServers”個子程序後,為了滿足MinSpareServers設定的需要建立一個程序,等待一秒鐘,繼續建立兩 個,再等待一秒鐘,繼續建立四個……如此按指數級增加建立的程序數,最多達到每秒32個,直到滿足MinSpareServers設定的值為止

設定springboot自帶tomcat的連線併發

從原始碼來看,最大連線數和最大併發數預設是10000和200 可以通過工程下的application.yml配置檔案來改變這個值 server:   tomcat:     uri-enco

Oracle併發&License情況

檢視當前license情況 SQL> show parameter license; NAME TYPE VALUE ----------------------------------

IIS 之 連線併發連線併發工作執行緒、佇列長度、工作程序數

轉載: 參考:https://blog.csdn.net/enweitech/article/details/79815137 https://blog.csdn.net/enweitech/article/details/79815137 https://blog.csdn.net/b

IIS併發連線

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Linux下高併發socket連線各種限制的調優

1、修改使用者程序可開啟檔案數限制  在Linux平臺上,無論編寫客戶端程式還是服務端程式,在進行高併發TCP連線處理時,最高的併發數量都要受到系統對使用者單一程序同時可開啟檔案數量的限制(這是因為系統為每個TCP連線都要建立一個socket控制代碼,每個socket控制代碼同時也是一個檔案控制代碼)。可使用

nginx併發連線的思考:worker_processes、worker_connections、worker_rlimit_nofile

無論是看過的nginx有關書還是網上看到的有關nginx 配置說明的文章(http://wiki.nginx.org/EventsModule#worker_connections),無一例外,在講到 worker_connections 和 max_clients這兩個概念的關係時都一致的一筆帶過