[PySide] Keeping GUI responsive

Israel Brewster ijbrewster at alaska.edu
Fri Dec 6 20:20:50 CET 2019


> On Dec 6, 2019, at 10:03 AM, Jason H <jhihn at gmx.com> wrote:
> 
> Do you processing function in C++, in a QThread or QRunnable.
> Have Python start the execution of that function in compiled code.
> At the end of processing have it signal the results to the main thread.
>  
> This means moving your work funtion into C++, and probably translating between Qt and python types (Shiboken should automate this I think?)

So if I am understanding you correctly, you are suggesting re-writing all the python processing code in C++? Yeah, that’s not going to happen. :-)

As far as “translating between Qt and python types”, considering that my python type is a Pandas data frame, I’d be surprised if there was a good/easy way to do this.

If it helps clarify the problem, the “large data structures” I mention are Pandas Data Frames, and the processing is not a simple loop, but rather an extended series of manipulations of said data frames. I’m not even sure I want to think about what it would take to port this to C++ :-D…

Some of the sample code I am dealing with, if it helps:

	so2_int_peak_centre_record = [self.mstr_df['record'][x] for x in self.so2_int_peak_centre_indx]
        h2s_int_peak_centre_record = [self.mstr_df['record'][x] for x in self.h2s_int_peak_centre_indx]
        co2_licor_peak_centre_record = [self.mstr_df['record'][x] for x in self.co2_licor_peak_centre_indx]

        # -------trig calculations to work out distance around arc between points
        right_angle_rad = 1.571
        self.contour_df['dUTMx'] = self.contour_df['UTMx'].shift(1) - self.contour_df['UTMx']
        self.contour_df['dUTMy'] = self.contour_df['UTMy'].shift(1) - self.contour_df['UTMy']
        self.contour_df['dist_from_prev'] = distance_from_prev(self.contour_df['dUTMx'], self.contour_df['dUTMy'])
        self.contour_df['dist_from_prev'].fillna(0, inplace=True)  # infill NaN with 0
        self.contour_df['beta_rad'] = np.arctan(self.contour_df['dUTMx'] / self.contour_df['dUTMy'])
        self.contour_df['beta_rad'].fillna(0, inplace=True)  # infill NaN with 0
        self.contour_df['a'] = np.radians(self.wind_azimuth) - self.contour_df['beta_rad'] + right_angle_rad
        self.contour_df['len_cos_a'] = self.contour_df['dist_from_prev'] * abs(np.cos(self.contour_df['a']))

        # ------trig calculations to work out absolute distance between points and wind centroid
        self.contour_df['delta_utmx_volc'] = self.contour_df['UTMx'] - self.volcano_utmx
        self.contour_df['delta_utmy_volc'] = self.contour_df['UTMy'] - self.volcano_utmy
        self.contour_df['volc_theta'] = np.degrees(np.arctan(abs(self.contour_df['delta_utmx_volc']) / abs(self.contour_df['delta_utmy_volc'])))
        self.contour_df['volc_azimuth'] = np.nan

        for i in range(self.contour_df.index[0], self.contour_df.index.max()):
            dx = self.contour_df['delta_utmx_volc'][i]
            dy = self.contour_df['delta_utmy_volc'][i]

            if dx > 0 and dy > 0:
                self.contour_df['volc_azimuth'][i] = self.contour_df['volc_theta'][i]

            elif dx > 0 > dy:
                self.contour_df['volc_azimuth'][i] = 180 - self.contour_df['volc_theta'][i]

            elif dx < 0 and dy < 0:
                self.contour_df['volc_azimuth'][i] = 180 + self.contour_df['volc_theta'][i]

            elif dx < 0 < dy:
                self.contour_df['volc_azimuth'][i] = 360 - self.contour_df['volc_theta'][i]

            if i % 50 == 0:
                self.yield_thread()

        self.contour_df['volc_dist'] = np.sqrt((self.contour_df['delta_utmy_volc']**2) + (self.contour_df['delta_utmx_volc']**2))  # distance from point to volcano

This goes on for almost 200 lines. That one for loop there, simple as it is, takes about half a second to complete (even without the yield_thread in there). And this is just a portion of one of four similar functions I am trying to run. So yeah, not porting to C any time soon :-)

>  
>  
> To clarify the original objective:
>  
> Given that:
> A) python threads can not execute simultaneously due to the GIL (unless one thread releases the GIL, which does not appear to be the case in my code, or perhaps due to something with PySide), AND
> B) my code does not lend itself to using multiprocessing rather than threading due to the large data structures involved (thus the reason the calculations take a while) -
>  
> How can I keep the GUI responsive while the calculations proceed?
>  
> So far the only solution I have come up with is to periodically call QApplication.processEvents() on the main thread from within my calculation code, but that is ugly and, according to everything I see online, indicative of a bad design. As I don’t want a bad design, what is the alternative? Or is this simply one of the rare cases where that *is* the correct answer?
>  

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/pyside/attachments/20191206/ae37f924/attachment.html>


More information about the PySide mailing list