在Parallel.ForEach期间避免ProgressDialog冻结(C#Xamarin Android)

时间:2017-07-16 21:28:05

标签: c# android asynchronous parallel-processing progressdialog

根据stackoverflow上的主题和示例,我写了一个" IP地址服务器搜索器"尝试通过http连接到192.168.x.1 - 192.168.x.254的所有可能的IP地址,以找到在特定端口上服务的前2台PC。

它工作得很好,对话框显示和更新1 .... 254只要: - 我将连接超时保留在并行循环内的 2000ms 36秒),或者 - 我减少到 200ms ,但是在没有的情况下逐行使用Parallel(需要 22秒!:D)

但如果我通过设置加速进程:.ConnectTimeout = 200;并保持平行>> - 对话框停止在0%
- 在 8秒之后,它发现了2个IP,
- 完成作业,对话框消失   (没有进程更新:()

以下是按钮的代码:

<!-- language: lang-cs -->
btnSearchAddress.Click += delegate {
    // ... get IP address of the WifiManager
    _PzzCID._myIPstring = Formatter.FormatIpAddress(i);

    // SHOW % in a dialog bar
    ProgressDialog progress;            
    progress = new Android.App.ProgressDialog( this );
    progress.SetCancelable(false);  
    _dialogCancelled = false; // static bool ... defined below
    progress.SetButton(-3, "STOP", (sender, e) => { // cancelling the search
        _dialogCancelled = true;
    });
    progress.Max = _MaxIP; // =254
    progress.SetIcon(Android.Resource.Drawable.IcMenuSearch);
    progress.SetProgressStyle(ProgressDialogStyle.Horizontal);  
    progress.SetMessage("Tested / Found IP addresses...");  
    progress.Show();

    var task = Task.Run( async () => { 
        await Task.Yield(); // force to run the commands from now on Async
        _FIND( edtPort.Text, edtDevicename.Text ); 
        while ( ! _dialogCancelled ) { //
            await Task.Delay( TimeSpan.FromMilliseconds(100));
            RunOnUiThread(() => {
                progress.Progress = _started.Value;
                //progress.Notify(); // would cause "not locked by thread ..." error
            });             
        };
        await Task.WhenAll();
        if (progress.IsShowing)
            progress.Dismiss();

        for (int j = 0; j < _addresses.Count; j++) {
            _PzzCID.AddLog2List(_addresses[j]);
            if (j==0) RunOnUiThread(() => edtBaseurl1.Text = _addresses[0]); 
            if (j==1) RunOnUiThread(() => edtBaseurl2.Text = _addresses[1]);
        }    
    });
}; // btnSearchAddress.Click

这是异步调用搜索循环:

const int _MaxIP = 254;
public static bool _dialogCancelled = false;

public static MultiThreadValues.ThreadSafeInt _started  = new MultiThreadValues.ThreadSafeInt(); // how many servers responded 
public static MultiThreadValues.ThreadSafeInt _found    = new MultiThreadValues.ThreadSafeInt(); // how many servers responded 
public static MultiThreadValues.ThreadSafeList<string> _addresses = new MultiThreadValues.ThreadSafeList<string>(); // each IP with server, who responded


public static async void _FIND( string port, string name ) { 
    await Task.Yield();
    _started.Value = 0;
    _found.Value   = 0;
    _addresses.Clear();
    string p = _PzzCID._myIPstring;
    if (p == "") return;
    const Char _dot = '.';

    StringBuilder str192 = new StringBuilder(64);
    Int16 dots = 0;
    for (int c = 0; c < p.Length; c++) {
        if ( p[c] == _dot)  dots++;
        str192.Append(p[c]);
        if (dots == 3) break; // found 3. "." = 192.168.1.
    }
    string str192168 = str192.ToString();

    const Int16 _numberOfthreads = 8;

    IEnumerable<int> _all_1_to_254 = Enumerable.Range (1, _MaxIP);
    // Parallel.ForEach(GetRateLimitedResource,
    Parallel.ForEach(_all_1_to_254, new ParallelOptions() { MaxDegreeOfParallelism = _numberOfthreads }, 
    async (i, StopMe) => {
        await Task.Yield();
        _started.Add1();
        //int s = _started.Value;
        //if (s < _numberOfthreads) Thread.Sleep(500 * s); // useless

        bool success = false;
        var host0 = str192168 + i;
            string url_txt = WebCall.CreateTestURL(host0, port, name) ;
            URL myUrl = new URL (url_txt);
            try {
                using (HttpURLConnection urlc = (HttpURLConnection)myUrl.OpenConnection ()) {
                    urlc.RequestMethod = "GET";  //OR  urlc.setRequestMethod ("HEAD"); 
                    urlc.SetRequestProperty("Connection", "close");
                    urlc.ConnectTimeout = 200;
                    await urlc.ConnectAsync();
                    success = (urlc.ResponseCode == HttpStatus.Ok); 
                }
            }
            catch (Exception ex) {
                //_addresses.Add("**ERROR:"+url_txt+ " --- " + ex.Message);
            }
            myUrl.Dispose();

        if (success) {
            _found.Add1();
            _addresses.Add(host0);
            if (_found.Value == 2) {
                StopMe.Stop(); // Found 2 hosts >> Exit from for-loop
            }
        }

        if (_dialogCancelled &&  ! StopMe.IsStopped)   StopMe.Stop(); // StopMe is a ForEach state 
    }); // lambra ForEach

    _dialogCancelled = true; // force finish >> to dismiss the ProcessDialog automatically
} //void _FIND()

问:在CPU负载过重的情况下,如何强制更新(刷新)ProcessDialog?  (如果还有其他我可以改进的地方,请与我分享!)

0 个答案:

没有答案