Skip to main content
Code style: black

IDIM

Winloop

PyPI version PyPI - Downloads License: MIT License: Apache-2.0

An alternative library for uvloop compatibility with Windows because let's face it. Windows' Python asyncio standard library is garbage, especially when Windows Defender decides to eat half of your RAM. I never really liked the fact that I couldn't make anything run faster especially when you have fiber internet connections in place and you've done all the optimizations you could possibly think of. It always felt disappointing when libuv is available for Windows but Windows was never compatible with uvloop.

Since nobody was willing to step in after so many years of waiting, I went ahead and downloaded the source code for uvloop and started modifying the source code to be Windows compatible by carefully removing and changing parts that were not made for Windows. Many hours of research went into making this library.

The differences with uvloop is that forking has been fully disabled and some smaller API calls had to be changed, error handling has been carefully modified and subprocesses release the GIL instead of forking out...

There is a performance increase of about 5 times with Winloop compared to using the WindowsSelectorEventLoopPolicy and WindowsProactorEventLoopPolicy which have been known to trigger SSL problems in Python 3.9. Winloop is a very good replacement for solving those SSL problems as well. This library also has comparable performance to its brother uvloop.

How to install Winloop on your Windows Operating System

pip install winloop

You can also clone the repository and build the extension yourself by running the command below if you wish to use or build this library locally. Note that you will need Cython and The Visual C++ extensions to compile this library on your own.

python setup.py build_ext --inplace

Reporting issues

If you find any bugs with this library be sure to open up an issue in the issuetracker. Me and other contributors will be happy try to help you figure out and diagnose your problems.

Making pull requests

We encourage anyone to make pull-requests to Winloop, containing anything from spelling mistakes to vulnerability patches. Every little bit helps keep this library maintained and alive. Make sure that you are able to compile the library with the steps shown above. We plan to implement a nightly workflow to verify one's pull-request in the future.

try:
    import aiohttp
    import aiohttp.web
except ImportError:
    skip_tests = True
else:
    skip_tests = False

import asyncio
import unittest
import weakref
import winloop
import sys

class TestAioHTTP(unittest.TestCase):
    def __init__(self, methodName: str = "test_aiohttp_basic_1") -> None:
        super().__init__(methodName)


    def setUp(self):
        self.loop = asyncio.get_event_loop()

    def test_aiohttp_basic_1(self):
        PAYLOAD = '<h1>It Works!</h1>' * 10000

        async def on_request(request):
            return aiohttp.web.Response(text=PAYLOAD)

        asyncio.set_event_loop(self.loop)
        app = aiohttp.web.Application()
        app.router.add_get('/', on_request)

        runner = aiohttp.web.AppRunner(app)
        self.loop.run_until_complete(runner.setup())
        site = aiohttp.web.TCPSite(runner, '0.0.0.0', '10000')
        self.loop.run_until_complete(site.start())
        port = site._server.sockets[0].getsockname()[1]

        async def test():
            # Make sure we're using the correct event loop.
            self.assertIs(asyncio.get_event_loop(), self.loop)

            for addr in (('localhost', port),
                         ('127.0.0.1', port)):
                async with aiohttp.ClientSession() as client:
                    async with client.get('http://{}:{}'.format(*addr)) as r:
                        self.assertEqual(r.status, 200)
                        result = await r.text()
                        self.assertEqual(result, PAYLOAD)

        self.loop.run_until_complete(test())
        self.loop.run_until_complete(runner.cleanup())

    def test_aiohttp_graceful_shutdown(self):
        async def websocket_handler(request):
            ws = aiohttp.web.WebSocketResponse()
            await ws.prepare(request)
            request.app['websockets'].add(ws)
            try:
                async for msg in ws:
                    await ws.send_str(msg.data)
            finally:
                request.app['websockets'].discard(ws)
            return ws

        async def on_shutdown(app):
            for ws in set(app['websockets']):
                await ws.close(
                    code=aiohttp.WSCloseCode.GOING_AWAY,
                    message='Server shutdown')

        asyncio.set_event_loop(self.loop)
        app = aiohttp.web.Application()
        app.router.add_get('/', websocket_handler)
        app.on_shutdown.append(on_shutdown)
        app['websockets'] = weakref.WeakSet()

        runner = aiohttp.web.AppRunner(app)
        self.loop.run_until_complete(runner.setup())
        site = aiohttp.web.TCPSite(runner, '0.0.0.0', '10000')
        self.loop.run_until_complete(site.start())
        port = site._server.sockets[0].getsockname()[1]

        async def client():
            async with aiohttp.ClientSession() as client:
                async with client.ws_connect(
                        'http://127.0.0.1:{}'.format(port)) as ws:
                    await ws.send_str("hello")
                    async for msg in ws:
                        assert msg.data == "hello"

        client_task = asyncio.ensure_future(client())

        async def stop():
            await asyncio.sleep(0.1)
            try:
                await asyncio.wait_for(runner.cleanup(), timeout=0.1)
            except Exception as e:
                print(e)
            finally:
                try:
                    client_task.cancel()
                    await client_task
                except asyncio.CancelledError:
                    pass

        self.loop.run_until_complete(stop())



if __name__ == "__main__":
    # print("tesing without winloop")
    # asyncio.DefaultEventLoopPolicy = asyncio.WindowsSelectorEventLoopPolicy
    # asyncio.DefaultEventLoopPolicy = asyncio.WindowsProactorEventLoopPolicy
    unittest.main()
    # Looks like winloop might be 3x faster than the Proctor Event Loop , THAT's A HUGE IMPROVEMENT!
    print("testing again but with winloop enabled")
    winloop.install()
    unittest.main()

The benchmarks for the code above are as follows

Benchmarks

TCP Connections


Asyncio Event Loop Policy Time (in Seconds)
WinLoopPolicy 0.493s
WindowsProactorEventLoopPolicy 2.510s
WindowsSelectorEventLoopPolicy 2.723s

That's a massive increase and jump from just TCP alone! I'll be posting more benchmarks soon, as I modify more of the current test suites made by uvloop...

How to Use Winloop with Fastapi

This was a cool little script I put together just to make Fastapi that much faster to handle:

# TODO this code example is deprecated
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
import winloop
import uvicorn
import asyncio
import datetime

app = FastAPI()

@app.on_event("startup")
def make_assertion():
    # Check to make sure that we bypassed the original eventloop Policy....
    assert isinstance(asyncio.get_event_loop_policy(), winloop.WinLoopPolicy)


@app.get("/test")
async def test_get_request():
    return HTMLResponse("<html><body><h1>FAST API WORKS WITH WINLOOP!</h1></body></html>")


# starllete will use asyncio.to_thread() so that this can remain asynchronous
@app.get("/date")
def test_dynamic_response():
    return str(datetime.datetime.now())


# Although tricky to pass and is not normal, it does in fact work...
if __name__ == "__main__":
    winloop.install()
    # Winloop's eventlooppolicy will be passed to uvicorn after this point...
    loop = asyncio.get_event_loop()
    config = uvicorn.Config(app=app,port=10000,loop=loop)
    server = uvicorn.Server(config)
    asyncio.run(server.serve())

How To Use Winloop When Uvloop is not available

# Here's A small Example of using winloop when uvloop is not available to us
import sys
import aiohttp
import asyncio

async def main():
    async with aiohttp.ClientSession("https://httpbin.org") as client:
        async with client.get("/ip") as resp:
            print(await resp.json())

if __name__ == "__main__":
    if sys.platform in ('win32', 'cygwin', 'cli'):
        from winloop import run
    else:
        # if we're on apple or linux do this instead
        from uvloop import run
    run(main())

TODO-List

  • In Winloop 0.2.0 or before 2026 I would like to start planning to migrate to pytest so that things could be formatted a little better. A Migration Python script might be needed or looked into.

  • Update Fastapi Example to a more recent version of fastapi

  • Help Wanted. We're looking for other maintainers to help us.

  • Nightly Builds And Test Suite Workflows for anyone wanting to use newer unreleased versions. (Done, it runs now)

  • Adding in the necessary hooks for pyinstaller to compile this fast library to executable code even though hooks have been known to inflate the size of the .exe files. This is because calling hidden-imports for all the __init__.py modules might annoy some developers. (Luckily I'm aware of this issue because I've been doing this myself...) Update, This is now pending and I hope that it passes

  • write a workflow for nightly builds if necessary for verification of pull requests.

  • Update benchmarks (They are old) can't believe I maintained this project for over a year now...

Videos

Contributing

I put my heart and soul into this library ever since it began and any help is appreciated and means a lot to me, I have other things I wish to explore so every little bit helps

How Can I contribute?

  • I make and branch and make edits and then I do a pull requests before I just step in and add something new. This way you have time to review my additions, changes or feature beforehand.
  • Forking The library.
  • Fixing or editing workflows.
  • Finding and editing spelling mistakes.

Metadata

Release files for winloop 0.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for winloop 0.7.0
File Size Uploaded
winloop-0.7.0.tar.gz 2.7 MB Details

Built distributions (wheels)

Table of built distributions (wheels) for winloop 0.7.0
File
winloop-0.7.0-cp314-cp314t-win_arm64.whl CPython 3.14 CPython 3.14 free-threading Windows ARM64 Details
winloop-0.7.0-cp314-cp314t-win_amd64.whl CPython 3.14 CPython 3.14 free-threading Windows x86-64 Details
winloop-0.7.0-cp314-cp314-win_arm64.whl CPython 3.14 CPython 3.14 Windows ARM64 Details
winloop-0.7.0-cp314-cp314-win_amd64.whl CPython 3.14 CPython 3.14 Windows x86-64 Details
winloop-0.7.0-cp313-cp313-win_arm64.whl CPython 3.13 CPython 3.13 Windows ARM64 Details
winloop-0.7.0-cp313-cp313-win_amd64.whl CPython 3.13 CPython 3.13 Windows x86-64 Details
winloop-0.7.0-cp312-cp312-win_arm64.whl CPython 3.12 CPython 3.12 Windows ARM64 Details
winloop-0.7.0-cp312-cp312-win_amd64.whl CPython 3.12 CPython 3.12 Windows x86-64 Details
winloop-0.7.0-cp311-cp311-win_arm64.whl CPython 3.11 CPython 3.11 Windows ARM64 Details
winloop-0.7.0-cp311-cp311-win_amd64.whl CPython 3.11 CPython 3.11 Windows x86-64 Details
winloop-0.7.0-cp310-cp310-win_arm64.whl CPython 3.10 CPython 3.10 Windows ARM64 Details
winloop-0.7.0-cp310-cp310-win_amd64.whl CPython 3.10 CPython 3.10 Windows x86-64 Details
winloop-0.7.0-cp39-cp39-win_arm64.whl CPython 3.9 CPython 3.9 Windows ARM64 Details
winloop-0.7.0-cp39-cp39-win_amd64.whl CPython 3.9 CPython 3.9 Windows x86-64 Details

Total release size: 11.7 MB

Release files / winloop-0.7.0.tar.gz

Download URL winloop-0.7.0.tar.gz
Size 2.7 MB
Tags Source
SHA-256 checksum
How to use checksums
dcdea8aa687711e0a41cbe6280cb0957e2cb1f5dcbc51e65138503ea3a70ff7a
BLAKE2b-256 checksum
How to use checksums
ee19f11a72d288887c9ed6f4b033040231a73caf361ddbdaab92a9dc34af9ced
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.7.0-cp314-cp314t-win_arm64.whl

Download URL winloop-0.7.0-cp314-cp314t-win_arm64.whl
Size 652.2 kB
Tags CPython 3.14 CPython 3.14 free-threading Windows ARM64
SHA-256 checksum
How to use checksums
a1d646722537504fff6f7d39f73ed70d7a8ce7505c3751cfac3c798d6d6b3904
BLAKE2b-256 checksum
How to use checksums
69434e87aff10d190e126dd574ac38103e8b10749d7de66dd6442443199b467f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.7.0-cp314-cp314t-win_amd64.whl

Download URL winloop-0.7.0-cp314-cp314t-win_amd64.whl
Size 752.0 kB
Tags CPython 3.14 CPython 3.14 free-threading Windows x86-64
SHA-256 checksum
How to use checksums
81ea78f879f7a59f58c9f6b97a3fd1b249f9c6b4576705e05be520da05fb1172
BLAKE2b-256 checksum
How to use checksums
3b5733754ab6a97b65e4112123b275848635e7cd480933c05638e4d6cc258a37
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.7.0-cp314-cp314-win_arm64.whl

Download URL winloop-0.7.0-cp314-cp314-win_arm64.whl
Size 606.7 kB
Tags CPython 3.14 Windows ARM64
SHA-256 checksum
How to use checksums
7edb554a69d2d315e0713142cd831001f2f1fb9a796688077bd7b651d3bbb2f6
BLAKE2b-256 checksum
How to use checksums
51222709911d2ff28154657c60a9119c4224347087edcc41f730631ecd4b2f8a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.7.0-cp314-cp314-win_amd64.whl

Download URL winloop-0.7.0-cp314-cp314-win_amd64.whl
Size 696.5 kB
Tags CPython 3.14 Windows x86-64
SHA-256 checksum
How to use checksums
ff5d7552f7ef189d99f3097ce4e0bc17c002e3ced1e01fcbcdebfeff050a717b
BLAKE2b-256 checksum
How to use checksums
ce8cf19225e0ea9f95102e1b6a6893db76ab2f345ef0bf92b8d986c67927929e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.7.0-cp313-cp313-win_arm64.whl

Download URL winloop-0.7.0-cp313-cp313-win_arm64.whl
Size 593.8 kB
Tags CPython 3.13 Windows ARM64
SHA-256 checksum
How to use checksums
552c901afead131739c3f1a7a219fe2fcf3b8e1a0428b92f3530950997961acd
BLAKE2b-256 checksum
How to use checksums
2a00a6fd76635e3726cb37047c3548820ae0af7991740d4f28899362841f1ead
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.7.0-cp313-cp313-win_amd64.whl

Download URL winloop-0.7.0-cp313-cp313-win_amd64.whl
Size 686.1 kB
Tags CPython 3.13 Windows x86-64
SHA-256 checksum
How to use checksums
af9a18e9f22dece1d9161a6fe3d6597e8429cb29d98b2fccb914f7699371b19d
BLAKE2b-256 checksum
How to use checksums
93056b1aa396f83a9c9b04089aa01606f0c55acc1ecfbacad032491e63baae28
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.7.0-cp312-cp312-win_arm64.whl

Download URL winloop-0.7.0-cp312-cp312-win_arm64.whl
Size 594.0 kB
Tags CPython 3.12 Windows ARM64
SHA-256 checksum
How to use checksums
23185a1c414cd327754671b982ac52bd10d2090b30139cf74e3168c30c9d1bf2
BLAKE2b-256 checksum
How to use checksums
05037c6a8ab38a30607415b067395edc3e0d128091222da5b5f0fd66f153b6cb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.7.0-cp312-cp312-win_amd64.whl

Download URL winloop-0.7.0-cp312-cp312-win_amd64.whl
Size 687.2 kB
Tags CPython 3.12 Windows x86-64
SHA-256 checksum
How to use checksums
7c76d88db62d4246e7812cbdd28e9c628917104af0062e1add857cdb6857257c
BLAKE2b-256 checksum
How to use checksums
244ce7334c45b8a8a126a1cd97d5098ef45a5d0011fe2f8cc89a8612fe396fd5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.7.0-cp311-cp311-win_arm64.whl

Download URL winloop-0.7.0-cp311-cp311-win_arm64.whl
Size 594.7 kB
Tags CPython 3.11 Windows ARM64
SHA-256 checksum
How to use checksums
324f9f6293432ed52f09f8729f7576ff038d08754310b32ea7fcb433f9b03616
BLAKE2b-256 checksum
How to use checksums
6c786835e22f756ecd1e5dd00cd85b803b94e8c8683c40a3dc71a3c9e0cdc07e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.7.0-cp311-cp311-win_amd64.whl

Download URL winloop-0.7.0-cp311-cp311-win_amd64.whl
Size 664.9 kB
Tags CPython 3.11 Windows x86-64
SHA-256 checksum
How to use checksums
8f4ee09e36190bc77d820d793fe76d5ace48f83d9f8e39adde0231d0a0366011
BLAKE2b-256 checksum
How to use checksums
c2fe1fa36fb7ee8ba148dbadb5dbd61ac92a2526f8809ddf2eca8ba2020b24e2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.7.0-cp310-cp310-win_arm64.whl

Download URL winloop-0.7.0-cp310-cp310-win_arm64.whl
Size 592.8 kB
Tags CPython 3.10 Windows ARM64
SHA-256 checksum
How to use checksums
a159055cf2685bf77e42d62b3388a5b5dab3b36c8b35d3f4c6a354f987a59bdd
BLAKE2b-256 checksum
How to use checksums
49cdc6cba2b0f5fbb79cc02cded8baefe93ee3891eb84738ca8c95a7256208a0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.7.0-cp310-cp310-win_amd64.whl

Download URL winloop-0.7.0-cp310-cp310-win_amd64.whl
Size 656.6 kB
Tags CPython 3.10 Windows x86-64
SHA-256 checksum
How to use checksums
d61e1f6f372f64c1b08126b32e4dd4bde099d55c5a4f50ac54e6740c0cab2ed4
BLAKE2b-256 checksum
How to use checksums
97b93d71dd3d00b45145c90ff0f8a756a4e490dbb3fd9850a8aac20c5c7f9f5e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.7.0-cp39-cp39-win_arm64.whl

Download URL winloop-0.7.0-cp39-cp39-win_arm64.whl
Size 593.4 kB
Tags CPython 3.9 Windows ARM64
SHA-256 checksum
How to use checksums
8c5aec14af4567cfe0c635570feec9245d45737c3d4cff2d8898d80558d70367
BLAKE2b-256 checksum
How to use checksums
7de97386a5ff76bb62f2efa0b4dc9661ed11c4aa20163dd42fcf194f68c1b2cf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / winloop-0.7.0-cp39-cp39-win_amd64.whl

Download URL winloop-0.7.0-cp39-cp39-win_amd64.whl
Size 657.5 kB
Tags CPython 3.9 Windows x86-64
SHA-256 checksum
How to use checksums
3824863f1f1c4880df86c07605a35702e19edde93f64a581555c920a22377219
BLAKE2b-256 checksum
How to use checksums
0ed348161aeb59132928f9254622f77410139a73604a3b1e249600994a10233c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

0.7.0 This release

15 release files

0.6.4

15 release files

0.6.3

16 release files

0.6.2

16 release files

0.6.0

22 release files

0.5.0

22 release files

0.4.2

22 release files

0.4.1

22 release files

0.3.1

22 release files

0.3.0

22 release files

0.2.2

22 release files

0.2.1

22 release files

0.2.0

16 release files

0.1.8

7 release files

0.1.7

7 release files

0.1.6

6 release files

0.1.5

6 release files

0.1.4

6 release files

0.1.3

5 release files

0.1.2

5 release files

0.1.1

5 release files

0.1.0

5 release files

0.0.9

5 release files

0.0.8

5 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

1 release file

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page