C#中Invoke 和 BeginInvoke 的真正涵义

BeginInvoke 方法真的是新开一个线程进行异步调用吗?

参考以下代码:

public delegate void treeinvoke();
private void UpdateTreeView()
{
  MessageBox.Show(System.Threading.Thread.CurrentThread.Name);
}
private void button1_Click(object sender, System.EventArgs e)
{
  System.Threading.Thread.CurrentThread.Name = "UIThread";
  treeView1.BeginInvoke(new treeinvoke(UpdateTreeView));
}

看看运行结果,弹出的对话框中显示的是 UIThread,这说明 BeginInvoke 所调用的委托根本就是在 UI 线程中执行的。

既然是在 UI 线程中执行,又何来“异步执行”一说呢?

我们再看看下面的代码:

public delegate void treeinvoke();
private void UpdateTreeView()
{
  MessageBox.Show(Thread.CurrentThread.Name);
}
private void button1_Click(object sender, System.EventArgs e)
{
  Thread.CurrentThread.Name = "UIThread";
  Thread th = new Thread(new ThreadStart(StartThread));
  th.Start();
}
private void StartThread()
{
  Thread.CurrentThread.Name = "Work Thread";
  treeView1.BeginInvoke(new treeinvoke(UpdateTreeView));
}

再看看运行结果,弹出的对话框中显示的还是 UIThread,这说明什么?这说明 BeginInvoke 方法所调用的委托无论如何都是在 UI 线程中执行的。

那 BeginInvoke 究竟有什么用呢?

在多线程编程中,我们经常要在工作线程中去更新界面显示,而在多线程中直接调用界面控件的方法是错误的做法,具体的原因可以在看完我的这篇之后看看这篇:在多线程中如何调用Winform,如果你是大牛的话就不要看我这篇了,直接看那篇吧,反正那篇文章我没怎么看懂。

Invoke 和 BeginInvoke 就是为了解决这个问题而出现的,使你在多线程中安全的更新界面显示。

正确的做法是将工作线程中涉及更新界面的代码封装为一个方法,通过 Invoke 或者 BeginInvoke 去调用,两者的区别就是一个导致工作线程等待,而另外一个则不会。

而所谓的“一面响应操作,一面添加节点”永远只能是相对的,使 UI 线程的负担不至于太大而以,因为界面的正确更新始终要通过 UI 线程去做,我们要做的事情是在工作线程中包揽大部分的运算,而将对纯粹的界面更新放到 UI 线程中去做,这样也就达到了减轻 UI 线程负担的目的了。

而在那段更新树节点的代码中,其实唯一起作用的代码是:System.Threading.Thread.Sleep(100);,它使 UI 线程有了处理界面消息的机会,其实 数码幽灵 将问题复杂化了,只要以下的代码就可以很好的工作了。

private void button1_Click_(object sender, System.EventArgs e)
{
  TreeNode tn;
  for(int i=0;i<100000;i++)
  {
    tn=new TreeNode (i.ToString());
    this.treeView1.Nodes[0].Nodes.Add(tn);
    if (i%100 == 0) Application.DoEvents();
  }
}
时间: 2014-10-19

C# Ini文件操作实例

在开源中国看到的操作ini文件的,写的还不看,留着以后用 复制代码 代码如下: using System;using System.IO;using System.Runtime.InteropServices;using System.Text;using System.Collections;using System.Collections.Specialized; namespace wuyisky{ /**//**/ /**//// <summary> /// IniFiles的类 /

C#实现读写ini文件类实例

本文实例讲述了C#实现读写ini文件类.分享给大家供大家参考.具体如下: 这个C#类封装了对INI配置文件进行操作所需的各种函数,包括读取键值.读取键值.删除段落等 using System; using System.Runtime.InteropServices; using System.Text; namespace DotNet.Utilities { /// <summary> /// INI文件读写类. /// </summary> public class INIF

c#实现ini文件读写类分享

复制代码 代码如下: /// <summary>    /// 读写INI文件的类.    /// </summary>    public class INIHelper    {        // 读写INI文件相关.        [DllImport("kernel32.dll", EntryPoint = "WritePrivateProfileString", CharSet = CharSet.Ansi)]        pu

c# Invoke和BeginInvoke 区别分析

Control.Invoke 方法 (Delegate) :在拥有此控件的基础窗口句柄的线程上执行指定的委托. Control.BeginInvoke 方法 (Delegate) :在创建控件的基础句柄所在线程上异步执行指定委托. (一)Control的Invoke和BeginInvoke 我们要基于以下认识: (1)Control的Invoke和BeginInvoke与Delegate的Invoke和BeginInvoke是不同的. (2)Control的Invoke和BeginInvoke的

C#实现利用Windows API读写INI文件的方法

本文实例讲述了C#实现利用Windows API读写INI文件的方法.分享给大家供大家参考.具体如下: 写入时,如果没有INI文件,自动创建INI 如果在创建时,GetLastError:5 检查IniPath是否添加了文件名称.ini using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Runtime.InteropServices; namespace

C#操作INI配置文件示例详解

本文实例为大家分享了C#操作INI配置文件示例的具体代码,供大家参考,具体内容如下 源文件地址:C#操作INI配置文件示例 创建如图所示的控件: 源代码: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Win

C#中读写INI文件的方法例子

通常C#使用基于XML的配置文件,不过如果有需要的话,比如要兼顾较老的系统,可能还是要用到INI文件.但C#本身并不具备读写INI文件的API,只有通过调用非托管代码的方式,即系统自身的API才能达到所需的目的. 对应读写的方法分别为GetPrivateProfileString和WritePrivateProfileString. GetPrivateProfileString中的各参数:lpAppName -- section的名称lpKeyName -- key的名称lpDefault -

C# Winform 调用系统接口操作 INI 配置文件的代码

包括了写入和读取功能. 写入的时候, 如果文件不存在会自动创建. 如果对应的键已经存在, 则自动覆盖它的值. 读取的时候, 如果对应的文件不存在, 或者键名不存在, 则返回一个 empty 值. 非常方便 ^_^ 复制代码 代码如下: // 系统接口类 public static class WinAPI { [DllImport("kernel32")] // 写入配置文件的接口 private static extern long WritePrivateProfileString

c#读写ini配置文件示例

其他人写的都是调用非托管kernel32.dll.我也用过 但是感觉兼容性有点不好 有时候会出现编码错误,毕竟一个是以前的系统一个是现在的系统.咱来写一个纯C#的ini格式配置文件读取,其实就是文本文件读写啦.但是我们要做的绝不仅仅是这样 是为了访问操作的方便 更是为了以后的使用. 都知道ini格式的配置文件里各个配置项 其实就是一行一行的文本 key跟value 用等号隔开.像这样:grade=5 .各个配置项又进行分组 同类型的放到一起 称之为section 以中括号([])区分.像这样:[

C#线程 BeginInvoke和EndInvoke使用方法

开发语言:C#3.0 IDE:Visual Studio 2008 一.C#线程概述 在操作系统中一个进程至少要包含一个线程,然后,在某些时候需要在同一个进程中同时执行多项任务,或是为了提供程序的性能,将要执行的任务分解成多个子任务执行.这就需要在同一个进程中开启多个线程.我们使用C#编写一个应用程序(控制台或桌面程序都可以),然后运行这个程序,并打开windows任务管理器,这时我们就会看到这个应用程序中所含有的线程数,如下图所示. 如果任务管理器没有"线程数"列,可以[查看]>

python通过线程实现定时器timer的方法

本文实例讲述了python通过线程实现定时器timer的方法.分享给大家供大家参考.具体分析如下: 这个python类实现了一个定时器效果,调用非常简单,可以让系统定时执行指定的函数 下面介绍以threading模块来实现定时器的方法. 使用前先做一个简单试验: import threading def sayhello(): print "hello world" global t #Notice: use global variable! t = threading.Timer(5

Python实现在线程里运行scrapy的方法

本文实例讲述了Python实现在线程里运行scrapy的方法.分享给大家供大家参考.具体如下: 如果你希望在一个写好的程序里调用scrapy,就可以通过下面的代码,让scrapy运行在一个线程里. """ Code to run Scrapy crawler in a thread - works on Scrapy 0.8 """ import threading, Queue from twisted.internet import reac

python开发之基于thread线程搜索本地文件的方法

本文实例讲述了python开发之基于thread线程搜索本地文件的方法.分享给大家供大家参考,具体如下: 先来看看运行效果图: 利用多个线程处理搜索的问题,我们可以发现他很快.... 下面是代码部分: # A parallelized "find(1)" using the thread module. # This demonstrates the use of a work queue and worker threads. # It really does do more sta

Python3.X 线程中信号量的使用方法示例

前言 最近在学习python,发现了解线程信号量的基础知识,对深入理解python的线程会大有帮助.所以本文将给大家介绍Python3.X线程中信号量的使用方法,下面话不多说,来一起看看详细的介绍: 方法示例 线程中,信号量主要是用来维持有限的资源,使得在一定时间使用该资源的线程只有指定的数量 # -*- coding:utf-8 -*- """ Created by FizLin on 2017/07/23/-下午10:59 mail: https://github.com

C++线程池的简单实现方法

本文以实例形式较为详细的讲述了C++线程池的简单实现方法.分享给大家供大家参考之用.具体方法如下: 一.几个基本的线程函数: 1.线程操纵函数: int pthread_create(pthread_t *tidp, const pthread_attr_t *attr, (void*)(*start_rtn)(void *), void *arg); //创建 void pthread_exit(void *retval); //终止自身 int pthread_cancel(pthread_

ThreadPoolExecutor线程池原理及其execute方法(详解)

jdk1.7.0_79 对于线程池大部分人可能会用,也知道为什么用.无非就是任务需要异步执行,再者就是线程需要统一管理起来.对于从线程池中获取线程,大部分人可能只知道,我现在需要一个线程来执行一个任务,那我就把任务丢到线程池里,线程池里有空闲的线程就执行,没有空闲的线程就等待.实际上对于线程池的执行原理远远不止这么简单. 在Java并发包中提供了线程池类--ThreadPoolExecutor,实际上更多的我们可能用到的是Executors工厂类为我们提供的线程池:newFixedThreadP

Java线程中start和run方法全面解析

自定义线程两种方法 自定义一个runnable接口的实现类,然后构造一个thread,即对thread传入一个runnable接口类. new一个thread或者写个thread子类,覆盖它的run方法.(new 一个thread并覆盖run方法实际上是匿名内部类的一种方式) 示例代码 public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { System.

python使用装饰器和线程限制函数执行时间的方法

本文实例讲述了python使用装饰器和线程限制函数执行时间的方法.分享给大家供大家参考.具体分析如下: 很多时候函数内部包含了一些不可预知的事情,比如调用其它软件,从网络抓取信息,可能某个函数会卡在某个地方不动态,这段代码可以用来限制函数的执行时间,只需要在函数的上方添加一个装饰器,timelimited(2)就可以限定函数必须在2秒内执行完成,如果执行完成则返回函数正常的返回值,如果执行超时则会抛出错误信息. # -*- coding: utf-8 -*- from threading imp

C#往线程里传递参数的方法小结

传参方式有两种: 1.创建带参构造方法类 传参 2.利用Thread.start(8)直接传参,该方法会接收一个对象,并将该对象传递给线程,因此在线程中启动的方法 必须接收object类型的单个参数. Thread (ParameterizedThreadStart) 初始化 Thread 类的新实例,指定允许对象在线程启动时传递给线程的委托. Thread (ThreadStart) 初始化 Thread 类的新实例. 由 .NET Compact Framework 支持. Thread (