Asynchronous has been used in the project for a long time. For example, the web framework fastapi supports asynchronous writing. However, I only learned the writing method of "async/await", but can this writing method really make your program faster?
Asynchronous concept
-
synchronization
-
asynchronous
Synchronous VS asynchronous
Take a simulated visit to a website as an example to demonstrate the difference between synchronous and asynchronous.
-
synchronization
import time def visit_url(url, response_time): """ visit url """ print(f"visit: {time.time()} - {url}") time.sleep(response_time) print(f"response: {time.time()}") return f"visit{url}, Returned results" def run_task(): visit_url('http://itest.info', 2) visit_url('http://www.testpub.cn', 3) start_time = time.perf_counter() run_task() print(f"Elapsed time:{time.perf_counter() - start_time}")
Visit two websites respectively to simulate different time-consuming. The operation results are as follows:
visit: 1630638757.1427643 - http://itest.info response: 1630638759.1537898 visit: 1630638759.1537898 - http://www.testpub.cn response: 1630638762.1578455 Elapsed time: 5.0148674
-
asynchronous
Next, use asynchronous writing, rewrite the example, and add {async/await.
import asyncio import time async def visit_url(url, response_time): """visit url""" print(f"visit: {time.time()} - {url}") await asyncio.sleep(response_time) print(f"response: {time.time()}") async def run_task(): await visit_url('http://itest.info', 2) await visit_url('http://www.testpub.cn', 3) start_time = time.perf_counter() asyncio.run(run_task()) print(f"Elapsed time:{time.perf_counter() - start_time}")
-
Add {async to the function.
-
await is required to call async function.
Run the program again:
visit: 1630639557.2313683 - http://itest.info response: 1630639559.235232 visit: 1630639559.235232 - http://www.testpub.cn response: 1630639562.2393005 Elapsed time: 5.0091551999999995
You will find that there is no difference between the two runs.
If you want to achieve concurrency, you can create tasks through gather(). Modify run_task() function.
async def run_task(): url1 = visit_url('http://wangzhen.com', 2) url2 = visit_url('http://www.testpub.cn', 3) await asyncio.gather(url1, url2)
asyncio. The gather () method wraps multiple asynchronous tasks (two URLs) into a new asynchronous task.
Run the program again:
visit: 1630640450.1746979 - http://itest.info visit: 1630640450.1746979 - http://www.testpub.cn response: 1630640452.1871428 response: 1630640453.1928813 Elapsed time: 3.0196878000000003
From the results, it achieves the effect of concurrency. This is similar to the multi threading effect of python, but the asynchrony of Python is based on coroutines # to achieve concurrency.
Asynchronous test framework
Finally, we enter the topic and introduce the IsolatedAsyncioTestCase} class in python 3.8 unittest to realize asynchronous automatic testing.
from unittest import IsolatedAsyncioTestCase class Test(IsolatedAsyncioTestCase): async def asyncSetUp(self): print("asyncSetUp") async def test_response(self): print("test_response") async def asyncTearDown(self): print("asyncTearDown") if __name__ == "__main__": unittest.main()
At the syntactic level, async is added to each method. In order to verify this writing method, we introduce the httpx asynchronous HTTP library to fill in a specific use case.
import unittest import httpx class AsyncTest(unittest.IsolatedAsyncioTestCase): async def asyncSetUp(self): self.cli = httpx.AsyncClient() async def test_response(self): response = await self.cli.get("http://127.0.0.1:5000/") self.assertEqual(response.status_code, 200) async def test_response2(self): response = await self.cli.get("http://127.0.0.1:5000/") self.assertEqual(response.status_code, 200) async def asyncTearDown(self): await self.cli.aclose() if __name__ == "__main__": unittest.main()
I started a web service locally and set the interface to return in 2 seconds.
Run the above use case.
.. ---------------------------------------------------------------------- Ran 2 tests in 4.097s OK
From the results, it takes 4 seconds to call the two interfaces, which is no different from synchronization. Moreover, we can't simply transform it into a "concurrent" form, which will affect the statistics of test results, report generation and so on.
summary
-
Standing in the dimension of a single use case, the execution steps of the use case are sequential. I can't operate the page elements without opening the browser. Asynchronous writing is almost asexual.
-
From the perspective of multiple use cases, concurrency} can effectively improve the running speed, but it depends on whether the test framework supports concurrency. If concurrency is not supported, even if multithreading is forced to run use cases, what about the collection and statistical report of use case results? In addition, if concurrency is used, each use case must be absolutely independent, because different use cases must be thrown into different threads for execution. Therefore, there can be no use case dependency. For web UI automation, the browser must be opened / closed once for each use case, which will increase the resource consumption.
-
Asynchrony is mainly used in high concurrency scenarios, such as web services, web crawlers, database IO, etc. using asynchrony will significantly improve performance.
-
Why does unittest support asynchrony? It is not to use asynchrony to improve its execution speed, but to help you write test cases of asynchronous code more conveniently.
-
We see asynchrony in more and more projects, such as httpx, fastapi, aiofiles, aiomysql, playwright It is enough to show that he is a trend of programming in the future.