Skip to content

Commit f15e84f

Browse files
authored
Eliminate aio sender thread (#622)
1 parent 8f00cfc commit f15e84f

1 file changed

Lines changed: 7 additions & 45 deletions

File tree

zeroconf/aio.py

Lines changed: 7 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,10 @@
2121
"""
2222
import asyncio
2323
import contextlib
24-
import queue
25-
import threading
2624
from types import TracebackType # noqa # used in type hints
2725
from typing import Awaitable, Callable, Dict, List, Optional, Type, Union
2826

2927
from ._core import NotifyListener, Zeroconf
30-
from ._dns import DNSOutgoing
3128
from ._exceptions import NonUniqueNameException
3229
from ._services import ServiceInfo, _ServiceBrowserBase, instance_name_from_service_info
3330
from ._utils.aio import wait_condition_or_timeout
@@ -36,42 +33,6 @@
3633
from .const import _BROWSER_TIME, _CHECK_TIME, _LISTENER_TIME, _MDNS_PORT, _REGISTER_TIME, _UNREGISTER_TIME
3734

3835

39-
def _get_best_available_queue() -> queue.Queue:
40-
"""Create the best available queue type."""
41-
if hasattr(queue, "SimpleQueue"):
42-
return queue.SimpleQueue() # type: ignore # pylint: disable=all
43-
return queue.Queue()
44-
45-
46-
class _AsyncSender(threading.Thread):
47-
"""A thread to handle sending DNSOutgoing for asyncio."""
48-
49-
def __init__(self, zc: 'Zeroconf'):
50-
"""Create the sender thread."""
51-
super().__init__()
52-
self.zc = zc
53-
self.queue = _get_best_available_queue()
54-
self.start()
55-
self.name = "AsyncZeroconfSender"
56-
57-
def send(self, out: DNSOutgoing, addr: Optional[str] = None, port: int = _MDNS_PORT) -> None:
58-
"""Queue a send to be processed by the thread."""
59-
self.queue.put((out, addr, port))
60-
61-
def close(self) -> None:
62-
"""Close the instance."""
63-
self.queue.put(None)
64-
self.join()
65-
66-
def run(self) -> None:
67-
"""Runner that processes sends FIFO."""
68-
while True:
69-
event = self.queue.get()
70-
if event is None:
71-
return
72-
self.zc.send(*event)
73-
74-
7536
class AsyncNotifyListener(NotifyListener):
7637
"""A NotifyListener that async code can use to wait for events."""
7738

@@ -115,6 +76,7 @@ async def async_request(self, aiozc: 'AsyncZeroconf', timeout: float) -> bool:
11576
delay = _LISTENER_TIME
11677
next_ = now
11778
last = now + timeout
79+
await aiozc.zeroconf.async_wait_for_start()
11880
try:
11981
aiozc.zeroconf.add_listener(self, None)
12082
while not self._is_complete:
@@ -124,7 +86,7 @@ async def async_request(self, aiozc: 'AsyncZeroconf', timeout: float) -> bool:
12486
out = self.generate_request_query(aiozc.zeroconf, now)
12587
if not out.questions:
12688
return self.load_from_cache(aiozc.zeroconf)
127-
aiozc.sender.send(out)
89+
aiozc.zeroconf.async_send(out)
12890
next_ = now + delay
12991
delay *= 2
13092

@@ -180,7 +142,7 @@ async def async_run(self) -> None:
180142

181143
out = self.generate_ready_queries()
182144
if out:
183-
self.aiozc.sender.send(out, addr=self.addr, port=self.port)
145+
self.aiozc.zeroconf.async_send(out, addr=self.addr, port=self.port)
184146

185147
if not self._handlers_to_call:
186148
continue
@@ -236,15 +198,14 @@ def __init__(
236198
self.async_notify = AsyncNotifyListener(self)
237199
self.zeroconf.add_notify_listener(self.async_notify)
238200
self.async_browsers: Dict[AsyncServiceListener, AsyncServiceBrowser] = {}
239-
self.sender = _AsyncSender(self.zeroconf)
240201
self.condition = asyncio.Condition()
241202

242203
async def _async_broadcast_service(self, info: ServiceInfo, interval: int, ttl: Optional[int]) -> None:
243204
"""Send a broadcasts to announce a service at intervals."""
244205
for i in range(3):
245206
if i != 0:
246207
await asyncio.sleep(millis_to_seconds(interval))
247-
self.sender.send(self.zeroconf.generate_service_broadcast(info, ttl))
208+
self.zeroconf.async_send(self.zeroconf.generate_service_broadcast(info, ttl))
248209

249210
async def async_register_service(
250211
self,
@@ -261,6 +222,7 @@ async def async_register_service(
261222
The service will be broadcast in a task. This task is returned
262223
and therefore can be awaited if necessary.
263224
"""
225+
await self.zeroconf.async_wait_for_start()
264226
await self.async_check_service(info, cooperating_responders)
265227
self.zeroconf.registry.add(info)
266228
return asyncio.ensure_future(self._async_broadcast_service(info, _REGISTER_TIME, None))
@@ -274,7 +236,7 @@ async def async_check_service(self, info: ServiceInfo, cooperating_responders: b
274236
for i in range(3):
275237
if i != 0:
276238
await asyncio.sleep(millis_to_seconds(_CHECK_TIME))
277-
self.sender.send(self.zeroconf.generate_service_query(info))
239+
self.zeroconf.async_send(self.zeroconf.generate_service_query(info))
278240
self._raise_on_name_conflict(info)
279241

280242
def _raise_on_name_conflict(self, info: ServiceInfo) -> None:
@@ -304,13 +266,13 @@ async def async_update_service(self, info: ServiceInfo) -> Awaitable:
304266

305267
def _close(self) -> None:
306268
"""Shutdown zeroconf and the sender."""
307-
self.sender.close()
308269
self.zeroconf.remove_notify_listener(self.async_notify)
309270
self.zeroconf.close()
310271

311272
async def async_close(self) -> None:
312273
"""Ends the background threads, and prevent this instance from
313274
servicing further queries."""
275+
await self.zeroconf.async_wait_for_start()
314276
await self.async_remove_all_service_listeners()
315277
await self.loop.run_in_executor(None, self._close)
316278

0 commit comments

Comments
 (0)