public function socketPerform()
    {
        if ($this->count() == 0) {
            throw new Exception('Cannot perform if there are no requests in queue.');
        }

        $notRunning = $this->getRequestsNotRunning();
        do {
            /**
             * Apply cURL options to new requests
             */
            foreach ($notRunning as $request) {
                $this->getDefaultOptions()->applyTo($request);
                $request->getOptions()->applyTo($request);
                curl_multi_add_handle($this->mh, $request->getHandle());
                $this->running[$request->getUID()] = $request;
            }

            $runningHandles = null;
            do {
                // http://curl.haxx.se/libcurl/c/curl_multi_perform.html
                // If an added handle fails very quickly, it may never be counted as a running_handle.
                $mrc = curl_multi_exec($this->mh, $runningHandles);
            } while ($mrc === CURLM_CALL_MULTI_PERFORM);

            if ($runningHandles < count($this->running)) {
                $this->read();
            }

            $notRunning = $this->getRequestsNotRunning();
        } while (count($notRunning) > 0);
        // Why the loop? New requests might be added at runtime on 'complete' event.
        // So we need to attach them to curl_multi handle immediately.

        return $this->count() > 0;
    }