From a2e67645d16f031df724361e9e6596fd08498332 Mon Sep 17 00:00:00 2001 From: Noah Stapp Date: Tue, 1 Oct 2024 12:02:24 -0400 Subject: [PATCH 1/5] PYTHON-4784 - Add tests to confirm async parallelism --- test/asynchronous/test_concurrency.py | 54 +++++++++++++++++++++++++++ tools/synchro.py | 2 +- 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 test/asynchronous/test_concurrency.py diff --git a/test/asynchronous/test_concurrency.py b/test/asynchronous/test_concurrency.py new file mode 100644 index 0000000000..eab37f1316 --- /dev/null +++ b/test/asynchronous/test_concurrency.py @@ -0,0 +1,54 @@ +# Copyright 2024-present MongoDB, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Tests to ensure that the async API is properly concurrent with asyncio.""" +from __future__ import annotations + +import asyncio +import time +from test.asynchronous import AsyncIntegrationTest +from test.utils import delay + +_IS_SYNC = False + + +class TestAsyncConcurrency(AsyncIntegrationTest): + async def _task(self, client): + await client.db.test.find_one({"$where": delay(1)}) + + async def test_concurrency(self): + tasks = [] + iterations = 5 + + client = self.simple_client() + await client.db.test.drop() + await client.db.test.insert_one({"x": 1}) + + start = time.time() + + for _ in range(iterations): + await self._task(client) + + sequential_time = time.time() - start + start = time.time() + + for i in range(iterations): + tasks.append(self._task(client)) + + await asyncio.gather(*tasks) + concurrent_time = time.time() - start + + percent_faster = (sequential_time - concurrent_time) / concurrent_time * 100 + # We expect the concurrent tasks to be at least 50% faster + self.assertGreaterEqual(percent_faster, 50) diff --git a/tools/synchro.py b/tools/synchro.py index c5b0afb643..31efde0e84 100644 --- a/tools/synchro.py +++ b/tools/synchro.py @@ -149,7 +149,7 @@ def async_only_test(f: str) -> bool: """Return True for async tests that should not be converted to sync.""" - return f in ["test_locks.py"] + return f in ["test_locks.py", "test_concurrency.py"] test_files = [ From 9107bdab54a964fcfccc50e04597b0fb0d86ecbd Mon Sep 17 00:00:00 2001 From: Noah Stapp Date: Tue, 1 Oct 2024 14:25:11 -0400 Subject: [PATCH 2/5] Disable test on SSL until PYTHON-4636 fixes async performance --- test/asynchronous/test_concurrency.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/asynchronous/test_concurrency.py b/test/asynchronous/test_concurrency.py index eab37f1316..3eaed356ed 100644 --- a/test/asynchronous/test_concurrency.py +++ b/test/asynchronous/test_concurrency.py @@ -17,7 +17,7 @@ import asyncio import time -from test.asynchronous import AsyncIntegrationTest +from test.asynchronous import AsyncIntegrationTest, async_client_context from test.utils import delay _IS_SYNC = False @@ -27,11 +27,13 @@ class TestAsyncConcurrency(AsyncIntegrationTest): async def _task(self, client): await client.db.test.find_one({"$where": delay(1)}) + # Remove once PYTHON-4636 is merged + @async_client_context.require_no_tls async def test_concurrency(self): tasks = [] iterations = 5 - client = self.simple_client() + client = await self.async_single_client() await client.db.test.drop() await client.db.test.insert_one({"x": 1}) From d554e5bfdd711fa01097071929aaeade38b825bb Mon Sep 17 00:00:00 2001 From: Noah Stapp Date: Thu, 3 Oct 2024 15:23:25 -0400 Subject: [PATCH 3/5] Vastly improve performance --- test/asynchronous/test_concurrency.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/asynchronous/test_concurrency.py b/test/asynchronous/test_concurrency.py index 3eaed356ed..d1ed8e313d 100644 --- a/test/asynchronous/test_concurrency.py +++ b/test/asynchronous/test_concurrency.py @@ -25,10 +25,8 @@ class TestAsyncConcurrency(AsyncIntegrationTest): async def _task(self, client): - await client.db.test.find_one({"$where": delay(1)}) + await client.db.test.find_one({"$where": delay(0.05)}) - # Remove once PYTHON-4636 is merged - @async_client_context.require_no_tls async def test_concurrency(self): tasks = [] iterations = 5 @@ -52,5 +50,5 @@ async def test_concurrency(self): concurrent_time = time.time() - start percent_faster = (sequential_time - concurrent_time) / concurrent_time * 100 - # We expect the concurrent tasks to be at least 50% faster - self.assertGreaterEqual(percent_faster, 50) + # We expect the concurrent tasks to be at least twice as fast + self.assertGreaterEqual(percent_faster, 100) From a4dd0c64f9210ad70a5b83cec7b4a7124025bdcf Mon Sep 17 00:00:00 2001 From: Noah Stapp Date: Mon, 7 Oct 2024 08:11:56 -0400 Subject: [PATCH 4/5] Improve consistency of test --- test/asynchronous/test_concurrency.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/asynchronous/test_concurrency.py b/test/asynchronous/test_concurrency.py index d1ed8e313d..e02d40170e 100644 --- a/test/asynchronous/test_concurrency.py +++ b/test/asynchronous/test_concurrency.py @@ -25,7 +25,7 @@ class TestAsyncConcurrency(AsyncIntegrationTest): async def _task(self, client): - await client.db.test.find_one({"$where": delay(0.05)}) + await client.db.test.find_one({"$where": delay(0.10)}) async def test_concurrency(self): tasks = [] @@ -50,5 +50,5 @@ async def test_concurrency(self): concurrent_time = time.time() - start percent_faster = (sequential_time - concurrent_time) / concurrent_time * 100 - # We expect the concurrent tasks to be at least twice as fast - self.assertGreaterEqual(percent_faster, 100) + # We expect the concurrent tasks to be at least 75% faster on all platforms as a conservative benchmark + self.assertGreaterEqual(percent_faster, 75) From b35704d0101753623dad1e3bfde51a400ec7cbc4 Mon Sep 17 00:00:00 2001 From: Noah Stapp Date: Mon, 7 Oct 2024 09:23:31 -0400 Subject: [PATCH 5/5] Improve consistency of test again --- test/asynchronous/test_concurrency.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/asynchronous/test_concurrency.py b/test/asynchronous/test_concurrency.py index e02d40170e..1683b8413b 100644 --- a/test/asynchronous/test_concurrency.py +++ b/test/asynchronous/test_concurrency.py @@ -25,7 +25,7 @@ class TestAsyncConcurrency(AsyncIntegrationTest): async def _task(self, client): - await client.db.test.find_one({"$where": delay(0.10)}) + await client.db.test.find_one({"$where": delay(0.20)}) async def test_concurrency(self): tasks = []