Ios Grand Central Dispatch中线程限制的解决方法?

Ios Grand Central Dispatch中线程限制的解决方法?,ios,objective-c,grand-central-dispatch,Ios,Objective C,Grand Central Dispatch,有了它,您可以轻松地在非主线程上执行耗时的任务,避免阻塞主线程,并保持UI的响应性。只需使用dispatch\u async并在全局并发队列上执行任务 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // code }); 然而,像这样听起来太好而不真实的事情通常也有其缺点。在我们的iOS应用程序项目中大量使用了它之后,最近我们发现它有64个线程的限制。一旦我们达到极限,应

有了它,您可以轻松地在非主线程上执行耗时的任务,避免阻塞主线程,并保持UI的响应性。只需使用
dispatch\u async
并在全局并发队列上执行任务

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // code
});
然而,像这样听起来太好而不真实的事情通常也有其缺点。在我们的iOS应用程序项目中大量使用了它之后,最近我们发现它有64个线程的限制。一旦我们达到极限,应用程序将冻结/挂起。通过使用Xcode暂停应用程序,我们可以看到主线程由
信号量\u wait\u trap
控制

谷歌在网上的搜索证实,其他人也遇到了这个问题,但到目前为止还没有找到解决办法

已达到调度线程硬限制:64(调度线程太多 在同步操作中被阻塞)

确认在使用
dispatch\u sync
dispatch\u barrier\u async
时也会发生此问题

问题:
由于Grand Central Dispatch有64个线程的限制,是否有解决方法


提前谢谢

> P> >如果你有约束和决心,你可以释放你自己的GCD枷锁,然后使用pTrx走到每一个进程的线程限制上,正好相反,但是底线是这样的:如果你在GCD中遇到队列宽度限制,你可能会考虑重新评估你的并发方法。 在极端情况下,有两种方法可以达到极限:

  • 您可以通过阻塞系统调用在某些OS原语上阻塞64个线程。(I/O绑定)
  • 您可以合法地同时拥有64个可运行任务。(CPU限制)
  • 如果您处于情况#1,那么推荐的方法是使用非阻塞I/O。事实上,GCD在10.7/Lion IIRC中引入了一系列调用,这些调用有助于异步调度I/O并改进线程重用。如果您使用GCD I/O机制,那么这些线程将不会在等待I/O时被占用,当文件描述符(或mach端口)上的数据可用时,GCD将只对块(或函数)进行排队。有关详细信息,请参阅文档

    如果有帮助,下面是一个使用GCD I/O机制实现的TCP echo服务器的小示例(不提供担保):

    in_port_t port = 10000;
    void DieWithError(char *errorMessage);
    
    // Returns a block you can call later to shut down the server -- caller owns block.
    dispatch_block_t CreateCleanupBlockForLaunchedServer()
    {
        // Create the socket
        int servSock = -1;
        if ((servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
            DieWithError("socket() failed");
        }
    
        // Bind the socket - if the port we want is in use, increment until we find one that isn't
        struct sockaddr_in echoServAddr;
        memset(&echoServAddr, 0, sizeof(echoServAddr));
        echoServAddr.sin_family = AF_INET;
        echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        do {
            printf("server attempting to bind to port %d\n", (int)port);
            echoServAddr.sin_port = htons(port);
        } while (bind(servSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0 && ++port);
    
        // Make the socket non-blocking
        if (fcntl(servSock, F_SETFL, O_NONBLOCK) < 0) {
            shutdown(servSock, SHUT_RDWR);
            close(servSock);
            DieWithError("fcntl() failed");
        }
    
        // Set up the dispatch source that will alert us to new incoming connections
        dispatch_queue_t q = dispatch_queue_create("server_queue", DISPATCH_QUEUE_CONCURRENT);
        dispatch_source_t acceptSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, servSock, 0, q);
        dispatch_source_set_event_handler(acceptSource, ^{
            const unsigned long numPendingConnections = dispatch_source_get_data(acceptSource);
            for (unsigned long i = 0; i < numPendingConnections; i++) {
                int clntSock = -1;
                struct sockaddr_in echoClntAddr;
                unsigned int clntLen = sizeof(echoClntAddr);
    
                // Wait for a client to connect
                if ((clntSock = accept(servSock, (struct sockaddr *) &echoClntAddr, &clntLen)) >= 0)
                {
                    printf("server sock: %d accepted\n", clntSock);
    
                    dispatch_io_t channel = dispatch_io_create(DISPATCH_IO_STREAM, clntSock, q, ^(int error) {
                        if (error) {
                            fprintf(stderr, "Error: %s", strerror(error));
                        }
                        printf("server sock: %d closing\n", clntSock);
                        close(clntSock);
                    });
    
                    // Configure the channel...
                    dispatch_io_set_low_water(channel, 1);
                    dispatch_io_set_high_water(channel, SIZE_MAX);
    
                    // Setup read handler
                    dispatch_io_read(channel, 0, SIZE_MAX, q, ^(bool done, dispatch_data_t data, int error) {
                        BOOL close = NO;
                        if (error) {
                            fprintf(stderr, "Error: %s", strerror(error));
                            close = YES;
                        }
    
                        const size_t rxd = data ? dispatch_data_get_size(data) : 0;
                        if (rxd) {
                            // echo...
                            printf("server sock: %d received: %ld bytes\n", clntSock, (long)rxd);
                            // write it back out; echo!
                            dispatch_io_write(channel, 0, data, q, ^(bool done, dispatch_data_t data, int error) {});
                        }
                        else {
                            close = YES;
                        }
    
                        if (close) {
                            dispatch_io_close(channel, DISPATCH_IO_STOP);
                            dispatch_release(channel);
                        }
                    });
                }
                else {
                    printf("accept() failed;\n");
                }
            }
        });
    
        // Resume the source so we're ready to accept once we listen()
        dispatch_resume(acceptSource);
    
        // Listen() on the socket
        if (listen(servSock, SOMAXCONN) < 0) {
            shutdown(servSock, SHUT_RDWR);
            close(servSock);
            DieWithError("listen() failed");
        }
    
        // Make cleanup block for the server queue
        dispatch_block_t cleanupBlock = ^{
            dispatch_async(q, ^{
                shutdown(servSock, SHUT_RDWR);
                close(servSock);
                dispatch_release(acceptSource);
                dispatch_release(q);
            });
        };
    
        return Block_copy(cleanupBlock);
    }
    
    in_port\u t port=10000;
    无效DIEWERROR(字符*错误消息);
    //返回一个块,您可以稍后调用该块以关闭服务器--调用方拥有该块。
    dispatch_block_t CreateCleanupBlockForLaunchedServer()
    {
    //创建套接字
    int servSock=-1;
    if((servSock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0){
    DIEWERROR(“套接字()失败”);
    }
    //绑定套接字-如果我们想要的端口正在使用,则递增,直到找到一个未使用的端口
    echoServAddr中的结构sockaddr_;
    memset(&echoServAddr,0,sizeof(echoServAddr));
    echoServAddr.sin_family=AF_INET;
    echoServAddr.sin_addr.s_addr=htonl(INADDR_ANY);
    做{
    printf(“服务器试图绑定到端口%d\n”,(int)端口);
    echoServAddr.sinu端口=htons(端口);
    }而(bind(servSock,(struct sockaddr*)和echoServAddr,sizeof(echoServAddr))<0&&++port);
    //使插座不阻塞
    如果(fcntl(servSock、F_SETFL、O_NONBLOCK)<0){
    停机(servSock,停机(RDWR));
    关闭(servSock);
    DIEWERROR(“fcntl()失败”);
    }
    //设置调度源,以提醒我们新的传入连接
    调度队列q=调度队列创建(“服务器队列”,调度队列并发);
    dispatch\u source\u t acceptSource=dispatch\u source\u create(dispatch\u source\u TYPE\u READ,servSock,0,q);
    调度\u源\u集\u事件\u处理程序(acceptSource^{
    const unsigned long numPendingConnections=dispatch\u source\u get\u data(acceptSource);
    for(无符号长i=0;i=0)
    {
    printf(“服务器套接字:%d已接受\n”,clntSock);
    调度io t通道=调度io创建(调度io流,clntSock,q,^(int错误){
    如果(错误){
    fprintf(标准,“错误:%s”,标准错误(错误));
    }
    printf(“服务器套接字:%d关闭\n”,clntSock);
    关闭(clntSock);
    });
    //配置频道。。。
    调度低水位(通道1);
    调度高水位(通道,最大尺寸);
    //设置读取处理程序
    调度io读取(通道,0,最大大小,q,^(布尔完成,调度数据,整数错误){
    布尔关闭=否;
    如果(错误){
    fprintf(标准,“错误:%s”,标准错误(错误));
    关闭=是;
    }
    const size\u t rxd=数据?调度数据获取大小(数据):0;
    if(rxd){
    //回声。。。
    printf(“服务器套接字:%d已接收:%ld字节\n”,clntSock,(长)rxd);
    //把它写下来;回音!
    分派io写入(通道,0,数据,q,^(布尔完成,分派数据,int错误){});
    }
    否则{
    关闭=是;
    }
    如果(关闭){
    调度io关闭(通道,调度io停止);
    调度发布(通道);
    }
    });
    }
    否则{
    printf(“accept()失败;\n”);
    }
    }
    });
    //恢复源代码,以便我们准备好