Don't throw an exception every 10ms in the RPC worker

Cuts the time taken to run the react native tests on my machine from 198
seconds to 41 seconds. Probably has a similar impact on the react native
debugger performance.
This commit is contained in:
Thomas Goyne 2017-08-31 15:29:57 -07:00
parent c06daa795e
commit 7e1466b47a
2 changed files with 26 additions and 41 deletions

View File

@ -20,37 +20,26 @@
#include <condition_variable> #include <condition_variable>
#include <deque> #include <deque>
#include <exception>
#include <mutex> #include <mutex>
#include <realm/util/optional.hpp>
namespace realm { namespace realm {
class ConcurrentDequeTimeout : public std::exception {
public:
ConcurrentDequeTimeout() : std::exception() {}
};
template <typename T> template <typename T>
class ConcurrentDeque { class ConcurrentDeque {
public: public:
T pop_front(size_t timeout = 0) { T pop_back() {
std::unique_lock<std::mutex> lock(m_mutex); std::unique_lock<std::mutex> lock(m_mutex);
while (m_deque.empty()) { m_condition.wait(lock, [this] { return !m_deque.empty(); });
wait(lock, timeout); return do_pop_back();
}
T item = std::move(m_deque.front());
m_deque.pop_front();
return item;
} }
T pop_back(size_t timeout = 0) { util::Optional<T> try_pop_back(size_t timeout) {
std::unique_lock<std::mutex> lock(m_mutex); std::unique_lock<std::mutex> lock(m_mutex);
while (m_deque.empty()) { m_condition.wait_for(lock, std::chrono::milliseconds(timeout),
wait(lock, timeout); [this] { return !m_deque.empty(); });
} return m_deque.empty() ? util::none : util::make_optional(do_pop_back());
T item = std::move(m_deque.back());
m_deque.pop_back();
return item;
} }
void push_front(T&& item) { void push_front(T&& item) {
@ -72,19 +61,16 @@ class ConcurrentDeque {
return m_deque.empty(); return m_deque.empty();
} }
void wait(std::unique_lock<std::mutex> &lock, size_t timeout = 0) { private:
if (!timeout) {
m_condition.wait(lock);
}
else if (m_condition.wait_for(lock, std::chrono::milliseconds(timeout)) == std::cv_status::timeout) {
throw ConcurrentDequeTimeout();
}
}
private:
std::condition_variable m_condition; std::condition_variable m_condition;
std::mutex m_mutex; std::mutex m_mutex;
std::deque<T> m_deque; std::deque<T> m_deque;
T do_pop_back() {
T item = std::move(m_deque.back());
m_deque.pop_back();
return item;
}
}; };
} // realm } // realm

View File

@ -77,17 +77,16 @@ json RPCWorker::pop_task_result() {
} }
void RPCWorker::try_run_task() { void RPCWorker::try_run_task() {
try { // Use a 10 millisecond timeout to keep this thread unblocked.
// Use a 10 millisecond timeout to keep this thread unblocked. auto task = m_tasks.try_pop_back(10);
auto task = m_tasks.pop_back(10); if (!task) {
task(); return;
}
// Since this can be called recursively, it must be pushed to the front of the queue *after* running the task. (*task)();
m_futures.push_front(task.get_future());
} // Since this can be called recursively, it must be pushed to the front of the queue *after* running the task.
catch (ConcurrentDequeTimeout &) { m_futures.push_front(task->get_future());
// We tried.
}
} }
void RPCWorker::stop() { void RPCWorker::stop() {