winform和wpf里必知的多线程知识
背景: 很多小伙伴经常在群里问线程的问题,平时我经常转一些视频教程这些人不看,我就自己写个总结吧
不过还是要注意的是,切换本来就不能太频繁,要一口气改。
UI线程切换的核心思路是
1,这行代码会直接修改UI的,必须放在UI线程,掌握这条你可以自己把winform的线程检查关掉,将Control类的静态属性CheckForIllegalCrossThreadCalls设为false,必须心里有数才能做此操作
2,wpf也是如此,但是无法关闭线程检查,但是wpf的viewmodel就不需要UI线程,更新更方便,因为是内部通知的。
一,开启一个新的任务
var param = ; //net4.5以后
Task.Run(() =>
{
DoSomthing(param);
}); Task.Run(async () =>
{
await DoSomthingAsync(param);
}); //net 4.0 Task.Factory.StartNew(delegate ()
{
DoSomthing(param);
}); //3.5
Thread t = new Thread((ThreadStart)delegate ()
{
DoSomthing(param);
});
t.Start();
//net 3.5 加线程池
ThreadPool.QueueUserWorkItem((WaitCallback)delegate (Object obj)
{
DoSomthing(param);
});
后面都用Task为例
二, 回到UI线程
//winform
Task.Run(() =>
{
//类似sendMessage 等待发送结束
this.Invoke((Action)delegate ()
{
DoSomthing(param);
});
//类似postmessage 发了就跑
this.BeginInvoke((Action)delegate ()
{
DoSomthing(param);
});
}); //wpf
Task.Run(async () =>
{
this.Dispatcher.Invoke(delegate ()
{
DoSomthing(param);
}); //使用异步等待任务结束
await this.Dispatcher.BeginInvoke((Action)delegate ()
{
DoSomthing(param);
});
//使用抛弃返回值的方式,直接过 不等待
_ = this.Dispatcher.BeginInvoke((Action)delegate ()
{
DoSomthing(param);
});
});
await Task.Run(async () =>
{
DoSomething();
}
//回到调用线程
三, 高级方法
1 使用 SynchronizationContext
//在UI线程时记录下上下文
var syncContext = SynchronizationContext.Current;
Task.Run(() =>
{
//使用UI线程
syncContext.Post(o =>
{
DoSomthing(param);
}, null);
});
2 await一个SynchronizationContext
//在UI线程时记录下上下文
var syncContext = SynchronizationContext.Current;
Task.Run(() =>
{
//回到UI线程
await syncContext;
DoSomthing(param);//在UI线程中
});
那么如何await一个SynchronizationContext呢?
//写个Awaiter类
public sealed class SynchronizationContextAwaiter : INotifyCompletion
{
private readonly SynchronizationContext _context;
public SynchronizationContextAwaiter(SynchronizationContext context) =>
_context = context ?? throw new ArgumentNullException("context"); public bool IsCompleted => SynchronizationContext.Current == _context;
public void OnCompleted(Action action) => _context.Post(x => action(), null);
public void GetResult() { }
} //接下去使用awaiter类,写个扩展方法
public static SynchronizationContextAwaiter GetAwaiter(this SynchronizationContext context)
{
return new SynchronizationContextAwaiter(context);
}
四,将三的内容整合到一个类中
需要在UI线程初始化:
UIThreadContext.Init();
using Ruifei.Common.UIThread;
using System;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading; public static class UIThreadContext
{
public static SynchronizationContext Context;
public static Thread UIThread => uiThread;
static Thread uiThread = null;
public static void SendUIThread(Action action)
{
if (Context != null)
Context.Send(x => action(), null);
else
action();
} public static void SendUIThreadIfRequired(Action action)
{
Thread crt = Thread.CurrentThread;
if (uiThread != crt)
SendUIThread(action);
else
action();
} public static void PostUIThread(Action action)
{
if (Context != null)
Context.Post(x => action(), null);
else
action();
} public static void PostUIThread(Func<Task> action)
{
if (Context != null)
Context.Post(x => action(), null);
else
action();
} public static void PostUIThreadIfRequired(Action action)
{
if (IsInUIThread())
action();
else
PostUIThread(action);
} public static void PostUIThreadIfRequired(Func<Task> action)
{
if (IsInUIThread())
action();
else
PostUIThread(action);
} public static bool IsInUIThread()
{
return uiThread == Thread.CurrentThread;
} static Dispatcher dispatcher = (Application.Current != null && Application.Current.Dispatcher != null) ? Application.Current.Dispatcher : Dispatcher.CurrentDispatcher;
public async static void InvokeOnUIThread(Func<Task> action)
{
if (dispatcher == null || dispatcher.CheckAccess())
await action();
else
await dispatcher.BeginInvoke(action);
} public static void InvokeOnUIThread(Action action)
{
if (dispatcher == null || dispatcher.CheckAccess())
action();
else
dispatcher.BeginInvoke(action);
} public static void Init()
{
Context = SynchronizationContext.Current;
uiThread = Thread.CurrentThread;
} public static SynchronizationContextAwaiter GetAwaiter(this SynchronizationContext context)
{
return new SynchronizationContextAwaiter(context);
} /// <summary>
/// 切换到UI线程
/// </summary>
/// <returns></returns>
public static SynchronizationContext SwitchToUIThread()
{
return UIThreadContext.Context;
} /// <summary>
/// WithoutContext
/// </summary>
/// <returns></returns>
public static WaitForSwitchToNewTask SwitchToNewTask()
{
return new WaitForSwitchToNewTask(false);
}
} namespace Ruifei.Common.UIThread
{
public class WaitForSwitchToNewTask
{
bool withContext = false;
public WaitForSwitchToNewTask(bool _with)
{
withContext = _with;
}
public ConfiguredTaskAwaitable.ConfiguredTaskAwaiter GetAwaiter()
{
return Task.Run(() => { }).ConfigureAwait(withContext).GetAwaiter();
}
} public sealed class SynchronizationContextAwaiter : INotifyCompletion
{
private readonly SynchronizationContext _context;
public SynchronizationContextAwaiter(SynchronizationContext context) =>
_context = context ?? throw new ArgumentNullException("context"); public bool IsCompleted => SynchronizationContext.Current == _context;
public void OnCompleted(Action action)
{
if (_context == null)
{
action();
}
else
{
_context.Send(x => action(), null);
}
} public void GetResult() { }
}
}
winform和wpf里必知的多线程知识的更多相关文章
- python网络爬虫,知识储备,简单爬虫的必知必会,【核心】
知识储备,简单爬虫的必知必会,[核心] 一.实验说明 1. 环境登录 无需密码自动登录,系统用户名shiyanlou 2. 环境介绍 本实验环境采用带桌面的Ubuntu Linux环境,实验中会用到桌 ...
- input屏蔽历史记录 ;function($,undefined) 前面的分号是什么用处 JSON 和 JSONP 两兄弟 document.body.scrollTop与document.documentElement.scrollTop兼容 URL中的# 网站性能优化 前端必知的ajax 简单理解同步与异步 那些年,我们被耍过的bug——has
input屏蔽历史记录 设置input的扩展属性autocomplete 为off即可 ;function($,undefined) 前面的分号是什么用处 ;(function($){$.ex ...
- 15分钟带你了解前端工程师必知的javascript设计模式(附详细思维导图和源码)
15分钟带你了解前端工程师必知的javascript设计模式(附详细思维导图和源码) 前言 设计模式是一个程序员进阶高级的必备技巧,也是评判一个工程师工作经验和能力的试金石.设计模式是程序员多年工作经 ...
- 必知必会之 Java
必知必会之 Java 目录 不定期更新中-- 基础知识 数据计量单位 面向对象三大特性 基础数据类型 注释格式 访问修饰符 运算符 算数运算符 关系运算符 位运算符 逻辑运算符 赋值运算符 三目表达式 ...
- Java面试必知必会:基础
面试考察的知识点多而杂,要完全掌握需要花费大量的时间和精力.但是面试中经常被问到的知识点却没有多少,你完全可以用 20% 的时间去掌握 80% 常问的知识点. 一.基础 包括: 杂七杂八 面向对象 数 ...
- Visual Studio (VS IDE) 你必须知道的功能和技巧 - 【.Net必知系列】
前言 本文主要阐述一些Visual Studio开发下需要知道的少部分且比较实用的功能,也是很多人忽略的部分.一些不常用而且冷门的功能不在本文范围,当然本文的尾巴[.Net必知系列]纯属意淫,如有雷同 ...
- .NET程序员项目开发必知必会—Dev环境中的集成测试用例执行时上下文环境检查(实战)
Microsoft.NET 解决方案,项目开发必知必会. 从这篇文章开始我将分享一系列我认为在实际工作中很有必要的一些.NET项目开发的核心技术点,所以我称为必知必会.尽管这一系列是使用.NET/C# ...
- c++程序员必知的几个库
c++程序员必知的几个库 1.C++各大有名库的介绍——C++标准库 2.C++各大有名库的介绍——准标准库Boost 3.C++各大有名库的介绍——GUI 4.C++各大有名库的介绍——网络通信 5 ...
- 高效能人士必知铁律--note
偶然看到了<高效能人士 必知铁律>这本书,我比较少看成功学,但是这本书把很多著名的成功学书籍整理出来,有时会让你耳目一新,有些观点尽管是常识,但是却加深了你对它们的理解,比如: 只要在积极 ...
随机推荐
- Scrapy - response.css()
选择文本 response.css('span::text') 选择href response.css('a::attr(href)')
- S3C2440_时钟和电源管理_阅读开发手册记录
1.如何进入sleep mode 1)要把一些重要的数据存放在状态寄存器里,状态寄存器里的数据在掉电后不会丢失. 2)要设置好唤醒源 3)配置相关寄存器,使其进入sleep mode 2.如何从sle ...
- 学习laravel遇到的问题
1.今天学习使用form的组件,首先使用composer命令来引入: composer require illuminate/html 接着在blog/config/app.php中的两个地方添加内容 ...
- tab 切换 和 BottomNavigationBar 自定义 底部导航条
BottomNavigationBar 组件 BottomNavigationBar 是底部导航条,可以让我们定义底部 Tab 切换,bottomNavigationBar是 Scaffold ...
- 【前端之BOM和DOM】
" 目录 #. window对象介绍 #. window子对象 1. 浏览器对象 navigator 2. 屏幕对象 screen 3. 历史 history 4. 地址(URL) loc ...
- 「JSOI2015」字符串树
「JSOI2015」字符串树 传送门 显然可以树上差分. 我们对于树上每一条从根出发的路径都开一 棵 \(\text{Trie}\) 树,那么我们就只需要在 \(\text{Trie}\) 树中插入一 ...
- 关于SQL
set nocount on 作用 阻止在结果集中返回显示受t-sql语句影响的行计数信息 set nocount on 不返回计数,set nocount off 返回计数 即使当set nocou ...
- Spark性能调优-高级篇
前言 继基础篇讲解了每个Spark开发人员都必须熟知的开发调优与资源调优之后,本文作为<Spark性能优化指南>的高级篇,将深入分析数据倾斜调优与shuffle调优,以解决更加棘手的性能问 ...
- spring boot jpa 复杂查询 动态查询 连接and和or 模糊查询 分页查询
最近项目中用到了jpa,刚接触的时候有些激动,以前的到层忽然不用写sql不用去自己实现了,只是取个方法名就实现了,太惊艳了,惊为天人,但是慢慢的就发现不是这么回事了,在动态查询的时候,不知道怎么操作了 ...
- python查看包路径及对象的所有方法名
进入python环境: python 输入如下代码: import sys sys.path = sys.path[:] import django print(django.__path__) 得到 ...