How do I use Asyncio and GUI to read a file.

Viewed 1390

I have a text file with the names parsed with commas that looks like this:

Ann Marie,Smith,ams@companyname.com

The list could have over 100+ names in it. I left out the code that generates all the other GUI components to focus on loading the combobox and the items.

Problem:

How do I implement asyncio to read the text file without blocking the main thread to load the other GUI components.

This is the best I could come up with:

import wx
import asyncio


class Mywin(wx.Frame):

    def __init__(self, parent, title):
        super(Mywin, self).__init__(parent, title=title, size=(300, 200))


        self.panel = wx.Panel(self)
        box = wx.BoxSizer(wx.VERTICAL)
        self.eventloop()

        box.Add(self.combo, 1, wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5)
        box.AddStretchSpacer()

        self.panel.SetSizer(box)
        self.Centre()
        self.Show()

        #code to display and position GUI components left out


    async def readlist(self):
        filename = 'employees.txt'
        empList = []
        with open(filename) as f_obj:
            for line in f_obj:
                empList.append(line)
        return empList

    async def managecombobox(self, loop):
        task = loop.create_task(self.readlist())
        return_value = await task
        self.combo = wx.ComboBox(self.panel, choices=return_value)

    def eventloop(self):
        event_loop = asyncio.get_event_loop()
        try:
            event_loop.run_until_complete(self.managecombobox(event_loop))
        finally:
            event_loop.close()

    def OnCombo(self, event):
        self.label.SetLabel("You selected" + self.combo.GetValue() + " from Combobox")


app = wx.App()
Mywin(None, 'ComboBox Demo')
app.MainLoop() 
1 Answers

This function

async def readlist(self):
    filename = 'employees.txt'
    empList = []
    with open(filename) as f_obj:
        for line in f_obj:
            empList.append(line)
    return empList

is not asynchronous. The file reading is synchronous and no other task can run while this happens. Now since file reading is blocking by default it is not easy to make it asynchronous. One way is to submit the task to a separate thread:

import asyncio
from concurrent.futures import ThreadPoolExecutor

FileIOPool = ThreadPoolExecutor(8)  # you may pass here something like 2*CPU_CORES

class Mywin(wx.Frame):
    ...
    def read_file(self):
        filename = 'employees.txt'
        empList = []
        with open(filename) as f_obj:
            for line in f_obj:
                empList.append(line)
        return empList

    async def readlist(self):
        loop = asyncio.get_event_loop()
        return await loop.run_in_executor(FileIOPool, self.read_file)

Now readlist is truely asynchronous, other operations can run while the file is being read. This is a standard procedure when you want to apply some blocking task to asynchronous framework.

Related