使用线程遍历数组以每秒显示一项

本文关键字:显示 一项 线程 遍历 数组 | 更新日期: 2023-09-27 17:49:41

我试图创建一个while或for循环,使用线程按顺序显示索引字符串或int,以便它自动更改为下一个索引。这是我目前得到的。它在c#中,但计划在java中使用相同的信息。

private void button1_Click(object sender, EventArgs e)
{
    string st = "hello my name is miroslav glamuzina";
    string[] arr = st.Split(' ');
    int i = 0;
    while (i < arr.Length)
    {
        Thread.Sleep(50);
        label1.Text = arr[i];
        i++;
    }
}

使用线程遍历数组以每秒显示一项

TPL加上await使得真的很容易:

private async void button1_Click(object sender, EventArgs e)
{
    string st = "hello my name is miroslav glamuzina";
    string[] arr = st.Split(' ');
    foreach(string word in arr)
    {
        label1.Text = word;
        await Task.Delay(50);
    }
}

另一个选择是使用微软的响应式扩展(Rx)为您处理异步性。

下面是你的代码:
private SerialDisposable _subscription = new SerialDisposable();
private void button1_Click(object sender, EventArgs e)
{
    string st = "hello my name is miroslav glamuzina";
    string[] arr = st.Split(' ');
    _subscription.Disposable = 
        Observable
            .Interval(TimeSpan.FromMilliseconds(50.0))
            .Select(i => arr[(int)i])
            .Take(arr.Length)
            .ObserveOn(this)
            .Subscribe(word =>
            {
                label1.Text = word;
            });
}

现在,这段代码的好处是Subscribe方法返回一个IDisposable,可以用来在可观察对象查询完成之前停止它。有点像取消请求。现在,通过将此与SerialDisposable耦合,您将获得良好的行为,如果您的用户多次单击按钮,那么只有最新的订阅到可观察的查询将运行,如果现有的订阅正在运行,它将首先停止。

Rx还处理将代码推送到后台线程而不需要考虑它。ObserveOn(this)调用使线程重新在UI上运行,以便可以更新标签。

此代码在UI线程中工作,因此thread. sleep (X)休眠主应用程序线程。我建议你使用BackgroundWorker。

private void button1_Click(object sender, EventArgs e)
{
    System.ComponentModel.BackgroundWorker bw = new System.ComponentModel.BackgroundWorker();
    bw.DoWork += (sender, e) => 
    {
        string st = "hello my name is miroslav glamuzina";
        string[] arr = st.Split(' ');
        System.ComponentModel.BackgroundWorker worker = sender as System.ComponentModel.BackgroundWorker;
        for (int i = 0; i < arr.Length; i++)
        {                
            Thread.Sleep(500);
            worker.ReportProgress(i, arr[i]);
        }
    };
    bw.ProgressChanged += (sender, e) =>
    {
        label1.Text = e.UserState as string;
    };
    bw.RunWorkerAsync();
}

在这里使用线程确实是多余的。我也认为Task.Delay是最好的方法,如果你可以使用c# 5.0 async/await。然而,作为一种替代方法,这里有另一种使用yield和计时器的方法,也是基于编译器生成的状态机。它适用于c# 2.0及更高版本:

private void button1_Click(object sender, EventArgs e)
{
    this.button1.Enabled = false;
    Iterate();
}
IEnumerable GetIterator()
{
    string st = "hello my name is Noseratio";
    string[] arr = st.Split(' ');
    foreach (var s in arr)
    {
        label1.Text = s;
        yield return Type.Missing;
    }
}
void Iterate()
{
    var enumerator = GetIterator().GetEnumerator();
    var timer = new System.Windows.Forms.Timer();
    timer.Interval = 1000;
    timer.Tick += delegate
    {
        if (!enumerator.MoveNext())
        {
            timer.Dispose();
            this.button1.Enabled = true;
        }
    };
    timer.Start();
}