- 利用Requests Toolkit轻松完成HTTP请求
nseejrukjhad
http网络协议网络python
RequestsToolkit的力量:轻松构建HTTP请求Agent在现代软件开发中,API请求是与外部服务交互的核心。RequestsToolkit提供了一种便捷的方式,帮助开发者构建自动化的HTTP请求Agent。本文旨在详细介绍RequestsToolkit的设置、使用和潜在挑战。引言RequestsToolkit是一个强大的工具包,可用于构建执行HTTP请求的智能代理。这对于想要自动化与外
- 利用LangChain的StackExchange组件实现智能问答系统
nseejrukjhad
langchainmicrosoft数据库python
利用LangChain的StackExchange组件实现智能问答系统引言在当今的软件开发世界中,StackOverflow已经成为程序员解决问题的首选平台之一。而LangChain作为一个强大的AI应用开发框架,提供了StackExchange组件,使我们能够轻松地将StackOverflow的海量知识库集成到我们的应用中。本文将详细介绍如何使用LangChain的StackExchange组件
- node.js学习
小猿L
node.jsnode.js学习vim
node.js学习实操及笔记温故node.js,node.js学习实操过程及笔记~node.js学习视频node.js官网node.js中文网实操笔记githubcsdn笔记为什么学node.js可以让别人访问我们编写的网页为后续的框架学习打下基础,三大框架vuereactangular离不开node.jsnode.js是什么官网:node.js是一个开源的、跨平台的运行JavaScript的运行
- Python 实现图片裁剪(附代码) | Python工具
剑客阿良_ALiang
前言本文提供将图片按照自定义尺寸进行裁剪的工具方法,一如既往的实用主义。环境依赖ffmpeg环境安装,可以参考我的另一篇文章:windowsffmpeg安装部署_阿良的博客-CSDN博客本文主要使用到的不是ffmpeg,而是ffprobe也在上面这篇文章中的zip包中。ffmpy安装:pipinstallffmpy-ihttps://pypi.douban.com/simple代码不废话了,上代码
- 【无标题】达瓦达瓦
JhonKI
考研
博客主页:https://blog.csdn.net/2301_779549673欢迎点赞收藏⭐留言如有错误敬请指正!本文由JohnKi原创,首发于CSDN未来很长,值得我们全力奔赴更美好的生活✨文章目录前言111️111❤️111111111111111总结111前言111骗骗流量券,嘿嘿111111111111111111111111111️111❤️111111111111111总结11
- 上图为是否色发
JhonKI
考研
博客主页:https://blog.csdn.net/2301_779549673欢迎点赞收藏⭐留言如有错误敬请指正!本文由JohnKi原创,首发于CSDN未来很长,值得我们全力奔赴更美好的生活✨文章目录前言111️111❤️111111111111111总结111前言111骗骗流量券,嘿嘿111111111111111111111111111️111❤️111111111111111总结11
- 143234234123432
JhonKI
考研
博客主页:https://blog.csdn.net/2301_779549673欢迎点赞收藏⭐留言如有错误敬请指正!本文由JohnKi原创,首发于CSDN未来很长,值得我们全力奔赴更美好的生活✨文章目录前言111️111❤️111111111111111总结111前言111骗骗流量券,嘿嘿111111111111111111111111111️111❤️111111111111111总结11
- Python中深拷贝与浅拷贝的区别
yuxiaoyu.
转自:http://blog.csdn.net/u014745194/article/details/70271868定义:在Python中对象的赋值其实就是对象的引用。当创建一个对象,把它赋值给另一个变量的时候,python并没有拷贝这个对象,只是拷贝了这个对象的引用而已。浅拷贝:拷贝了最外围的对象本身,内部的元素都只是拷贝了一个引用而已。也就是,把对象复制一遍,但是该对象中引用的其他对象我不复
- ExpRe[25] bash外的其它shell:zsh和fish
tritone
ExpRebashlinuxubuntushell
文章目录zsh基础配置实用特性插件`autojump`语法高亮自动补全fish优点缺点时效性本篇撰写时间为2021.12.15,由于计算机技术日新月异,博客中所有内容都有时效和版本限制,具体做法不一定总行得通,链接可能改动失效,各种软件的用法可能有修改。但是其中透露的思想往往是值得学习的。本篇前置:ExpRe[10]Ubuntu[2]准备神秘软件、备份恢复软件https://www.cnblogs
- 一文掌握python面向对象魔术方法(二)
程序员neil
pythonpython开发语言
接上篇:一文掌握python面向对象魔术方法(一)-CSDN博客目录六、迭代和序列化:1、__iter__(self):定义迭代器,使得类可以被for循环迭代。2、__getitem__(self,key):定义索引操作,如obj[key]。3、__setitem__(self,key,value):定义赋值操作,如obj[key]=value。4、__delitem__(self,key):定义
- SpringCloudAlibaba—Sentinel(限流)
菜鸟爪哇
前言:自己在学习过程的记录,借鉴别人文章,记录自己实现的步骤。借鉴文章:https://blog.csdn.net/u014494148/article/details/105484410Sentinel介绍Sentinel诞生于阿里巴巴,其主要目标是流量控制和服务熔断。Sentinel是通过限制并发线程的数量(即信号隔离)来减少不稳定资源的影响,而不是使用线程池,省去了线程切换的性能开销。当资源
- Android应用性能优化
轻口味
Android
Android手机由于其本身的后台机制和硬件特点,性能上一直被诟病,所以软件开发者对软件本身的性能优化就显得尤为重要;本文将对Android开发过程中性能优化的各个方面做一个回顾与总结。Cache优化ListView缓存:ListView中有一个回收器,Item滑出界面的时候View会回收到这里,需要显示新的Item的时候,就尽量重用回收器里面的View;每次在getView函数中inflate新
- 光盘文件系统 (iso9660) 格式解析
穷人小水滴
光盘文件系统iso9660denoGNU/Linuxjavascript
越简单的系统,越可靠,越不容易出问题.光盘文件系统(iso9660)十分简单,只需不到200行代码,即可实现定位读取其中的文件.参考资料:https://wiki.osdev.org/ISO_9660相关文章:《光盘防水嘛?DVD+R刻录光盘泡水实验》https://blog.csdn.net/secext2022/article/details/140583910《光驱的内部结构及日常使用》ht
- springboot+vue项目实战一-创建SpringBoot简单项目
苹果酱0567
面试题汇总与解析springboot后端java中间件开发语言
这段时间抽空给女朋友搭建一个个人博客,想着记录一下建站的过程,就当做笔记吧。虽然复制zjblog只要一个小时就可以搞定一个网站,或者用cms系统,三四个小时就可以做出一个前后台都有的网站,而且想做成啥样也都行。但是就是要从新做,自己做的意义不一样,更何况,俺就是专门干这个的,嘿嘿嘿要做一个网站,而且从零开始,首先呢就是技术选型了,经过一番思量决定选择-SpringBoot做后端,前端使用Vue做一
- 科幻游戏 《外卖员模拟器》 主要地理环境设定 (1)
穷人小水滴
游戏科幻设计
游戏名称:《外卖员模拟器》(英文名称:waimai_se)作者:穷人小水滴本故事纯属虚构,如有雷同实属巧合.故事发生在一个(架空)平行宇宙的地球,21世纪(超低空科幻流派).相关文章:https://blog.csdn.net/secext2022/article/details/141790630目录1星球整体地理设定2巨蛇国主要设定3海蛇市主要设定3.1主要地标建筑3.2交通3.3能源(电力)
- 06选课支付模块之基于消息队列发送支付通知消息
echo 云清
学成在线javarabbitmq消息队列支付通知学成在线
消息队列发送支付通知消息需求分析订单服务作为通用服务,在订单支付成功后需要将支付结果异步通知给其他对接的微服务,微服务收到支付结果根据订单的类型去更新自己的业务数据技术方案使用消息队列进行异步通知需要保证消息的可靠性即生产端将消息成功通知到服务端:消息发送到交换机-->由交换机发送到队列-->消费者监听队列,收到消息进行处理,参考文章02-使用Docker安装RabbitMQ-CSDN博客生产者确
- C++ lambda闭包消除类成员变量
barbyQAQ
c++c++java算法
原文链接:https://blog.csdn.net/qq_51470638/article/details/142151502一、背景在面向对象编程时,常常要添加类成员变量。然而类成员一旦多了之后,也会带来干扰。拿到一个类,一看成员变量好几十个,就问你怕不怕?二、解决思路可以借助函数式编程思想,来消除一些不必要的类成员变量。三、实例举个例子:classClassA{public:...intfu
- tiff批量转png
诺有缸的高飞鸟
opencv图像处理pythonopencv图像处理
目录写在前面代码完写在前面1、本文内容tiff批量转png2、平台/环境opencv,python3、转载请注明出处:https://blog.csdn.net/qq_41102371/article/details/132975023代码importnumpyasnpimportcv2importosdeffindAllFile(base):file_list=[]forroot,ds,fsin
- 笋丁网页自动回复机器人V3.0.0免授权版源码
希希分享
软希网58soho_cn源码资源笋丁网页自动回复机器人
笋丁网页机器人一款可设置自动回复,默认消息,调用自定义api接口的网页机器人。此程序后端语言使用Golang,内存占用最高不超过30MB,1H1G服务器流畅运行。仅支持Linux服务器部署,不支持虚拟主机,请悉知!使用自定义api功能需要有一定的建站基础。源码下载:https://download.csdn.net/download/m0_66047725/89754250更多资源下载:关注我。安
- 博客网站制作教程
2401_85194651
javamaven
首先就是技术框架:后端:Java+SpringBoot数据库:MySQL前端:Vue.js数据库连接:JPA(JavaPersistenceAPI)1.项目结构blog-app/├──backend/│├──src/main/java/com/example/blogapp/││├──BlogApplication.java││├──config/│││└──DatabaseConfig.java
- 详解:如何设计出健壮的秒杀系统?
夜空_2cd3
作者:Yrion博客园:cnblogs.com/wyq178/p/11261711.html前言:秒杀系统相信很多人见过,比如京东或者淘宝的秒杀,小米手机的秒杀。那么秒杀系统的后台是如何实现的呢?我们如何设计一个秒杀系统呢?对于秒杀系统应该考虑哪些问题?如何设计出健壮的秒杀系统?本期我们就来探讨一下这个问题:image目录一:****秒杀系统应该考虑的问题二:****秒杀系统的设计和技术方案三:*
- 【树一线性代数】005入门
Owlet_woodBird
算法
Index本文稍后补全,推荐阅读:https://blog.csdn.net/weixin_60702024/article/details/141874376分析实现总结本文稍后补全,推荐阅读:https://blog.csdn.net/weixin_60702024/article/details/141874376已知非空二叉树T的结点值均为正整数,采用顺序存储方式保存,数据结构定义如下:t
- 非对称加密算法原理与应用2——RSA私钥加密文件
私语茶馆
云部署与开发架构及产品灵感记录RSA2048私钥加密
作者:私语茶馆1.相关章节(1)非对称加密算法原理与应用1——秘钥的生成-CSDN博客第一章节讲述的是创建秘钥对,并将公钥和私钥导出为文件格式存储。本章节继续讲如何利用私钥加密内容,包括从密钥库或文件中读取私钥,并用RSA算法加密文件和String。2.私钥加密的概述本文主要基于第一章节的RSA2048bit的非对称加密算法讲述如何利用私钥加密文件。这种加密后的文件,只能由该私钥对应的公钥来解密。
- Python 课程10-单元测试
可愛小吉
Python教學python单元测试开发语言TDDunittest
前言在现代软件开发中,单元测试已成为一种必不可少的实践。通过测试,我们可以确保每个功能模块在开发和修改过程中按预期工作,从而减少软件缺陷,提高代码质量。而测试驱动开发(TDD)则进一步将测试作为开发的核心部分,先编写测试,再编写代码,以测试为指导开发出更稳定、更可靠的代码。Python提供了强大的unittest模块,它是Python标准库的一部分,专门用于编写和执行单元测试。与其他测试框架相比,
- Ubuntu18.04 Docker部署Kinship(Django)项目过程
Dante617
1Docker的安装https://blog.csdn.net/weixin_41735055/article/details/1003551792下载镜像dockerpullprogramize/python3.6.8-dlib下载的镜像里包含python3.6.8和dlib19.17.03启动镜像dockerrun-it--namekinship-p7777:80-p3307:3306-p55
- C++常见知识掌握
nfgo
c++开发语言
1.Linux软件开发、调试与维护内核与系统结构Linux内核是操作系统的核心,负责管理硬件资源,提供系统服务,它是系统软件与硬件之间的桥梁。主要组成部分包括:进程管理:内核通过调度器分配CPU时间给各个进程,实现进程的创建、调度、终止等操作。使用进程描述符(task_struct)来存储进程信息,包括状态(就绪、运行、阻塞等)、优先级、内存映射等。内存管理:包括物理内存和虚拟内存管理。通过页表映
- 程序员架构师主要是做什么_程序员架构师:职责、技能与挑战
绿色小猪
免费备考资料(2024年11月软考):历年试题+视频课合集+电子讲义点击领取>>>免费刷题:2024年11月软考备考刷题点此进入>>>程序员架构师的角色定位在软件开发领域,程序员架构师是一个至关重要的角色。他们不仅需要深入理解业务需求,还要将其转化为技术上的解决方案。程序员架构师是项目中的技术领航者,负责制定和维护软件系统的整体架构,确保系统的可扩展性、可维护性和性能。他们的工作涉及从概念化到实现
- [Swift]LeetCode943. 最短超级串 | Find the Shortest Superstring
黄小二哥
swift
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/)➤GitHub地址:https://github.com/strengthen/LeetCode➤原文地址:https://www.cnblogs.com/streng
- [Swift]LeetCode767. 重构字符串 | Reorganize String
weixin_30591551
swiftruntime
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/)➤GitHub地址:https://github.com/strengthen/LeetCode➤原文地址:https://www.cnblogs.com/streng
- RK3229_Android9.0_Box 4G模块EC200A调试
suifen_
网络
0、kernel修改这部分完全可以参考Linux的移植:RK3588EC200A-CN【4G模块】调试_rkec200a-cn-CSDN博客1、修改device/rockchip/rk322xdiff--gita/device.mkb/device.mkindexec6bfaa..e7c32d1100755---a/device.mk+++b/device.mk@@-105,6+105,8@@en
- log4j对象改变日志级别
3213213333332132
javalog4jlevellog4j对象名称日志级别
log4j对象改变日志级别可批量的改变所有级别,或是根据条件改变日志级别。
log4j配置文件:
log4j.rootLogger=ERROR,FILE,CONSOLE,EXECPTION
#log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE=org.apache.l
- elk+redis 搭建nginx日志分析平台
ronin47
elasticsearchkibanalogstash
elk+redis 搭建nginx日志分析平台
logstash,elasticsearch,kibana 怎么进行nginx的日志分析呢?首先,架构方面,nginx是有日志文件的,它的每个请求的状态等都有日志文件进行记录。其次,需要有个队 列,redis的l
- Yii2设置时区
dcj3sjt126com
PHPtimezoneyii2
时区这东西,在开发的时候,你说重要吧,也还好,毕竟没它也能正常运行,你说不重要吧,那就纠结了。特别是linux系统,都TMD差上几小时,你能不痛苦吗?win还好一点。有一些常规方法,是大家目前都在采用的1、php.ini中的设置,这个就不谈了,2、程序中公用文件里设置,date_default_timezone_set一下时区3、或者。。。自己写时间处理函数,在遇到时间的时候,用这个函数处理(比较
- js实现前台动态添加文本框,后台获取文本框内容
171815164
文本框
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://w
- 持续集成工具
g21121
持续集成
持续集成是什么?我们为什么需要持续集成?持续集成带来的好处是什么?什么样的项目需要持续集成?... 持续集成(Continuous integration ,简称CI),所谓集成可以理解为将互相依赖的工程或模块合并成一个能单独运行
- 数据结构哈希表(hash)总结
永夜-极光
数据结构
1.什么是hash
来源于百度百科:
Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入,通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来唯一的确定输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。
- 乱七八糟
程序员是怎么炼成的
eclipse中的jvm字节码查看插件地址:
http://andrei.gmxhome.de/eclipse/
安装该地址的outline 插件 后重启,打开window下的view下的bytecode视图
http://andrei.gmxhome.de/eclipse/
jvm博客:
http://yunshen0909.iteye.com/blog/2
- 职场人伤害了“上司” 怎样弥补
aijuans
职场
由于工作中的失误,或者平时不注意自己的言行“伤害”、“得罪”了自己的上司,怎么办呢?
在职业生涯中这种问题尽量不要发生。下面提供了一些解决问题的建议:
一、利用一些轻松的场合表示对他的尊重
即使是开明的上司也很注重自己的权威,都希望得到下属的尊重,所以当你与上司冲突后,最好让不愉快成为过去,你不妨在一些轻松的场合,比如会餐、联谊活动等,向上司问个好,敬下酒,表示你对对方的尊重,
- 深入浅出url编码
antonyup_2006
应用服务器浏览器servletweblogicIE
出处:http://blog.csdn.net/yzhz 杨争
http://blog.csdn.net/yzhz/archive/2007/07/03/1676796.aspx
一、问题:
编码问题是JAVA初学者在web开发过程中经常会遇到问题,网上也有大量相关的
- 建表后创建表的约束关系和增加表的字段
百合不是茶
标的约束关系增加表的字段
下面所有的操作都是在表建立后操作的,主要目的就是熟悉sql的约束,约束语句的万能公式
1,增加字段(student表中增加 姓名字段)
alter table 增加字段的表名 add 增加的字段名 增加字段的数据类型
alter table student add name varchar2(10);
&nb
- Uploadify 3.2 参数属性、事件、方法函数详解
bijian1013
JavaScriptuploadify
一.属性
属性名称
默认值
说明
auto
true
设置为true当选择文件后就直接上传了,为false需要点击上传按钮才上传。
buttonClass
”
按钮样式
buttonCursor
‘hand’
鼠标指针悬停在按钮上的样子
buttonImage
null
浏览按钮的图片的路
- 精通Oracle10编程SQL(16)使用LOB对象
bijian1013
oracle数据库plsql
/*
*使用LOB对象
*/
--LOB(Large Object)是专门用于处理大对象的一种数据类型,其所存放的数据长度可以达到4G字节
--CLOB/NCLOB用于存储大批量字符数据,BLOB用于存储大批量二进制数据,而BFILE则存储着指向OS文件的指针
/*
*综合实例
*/
--建立表空间
--#指定区尺寸为128k,如不指定,区尺寸默认为64k
CR
- 【Resin一】Resin服务器部署web应用
bit1129
resin
工作中,在Resin服务器上部署web应用,通常有如下三种方式:
配置多个web-app
配置多个http id
为每个应用配置一个propeties、xml以及sh脚本文件
配置多个web-app
在resin.xml中,可以为一个host配置多个web-app
<cluster id="app&q
- red5简介及基础知识
白糖_
基础
简介
Red5的主要功能和Macromedia公司的FMS类似,提供基于Flash的流媒体服务的一款基于Java的开源流媒体服务器。它由Java语言编写,使用RTMP作为流媒体传输协议,这与FMS完全兼容。它具有流化FLV、MP3文件,实时录制客户端流为FLV文件,共享对象,实时视频播放、Remoting等功能。用Red5替换FMS后,客户端不用更改可正
- angular.fromJson
boyitech
AngularJSAngularJS 官方APIAngularJS API
angular.fromJson 描述: 把Json字符串转为对象 使用方法: angular.fromJson(json); 参数详解: Param Type Details json
string
JSON 字符串 返回值: 对象, 数组, 字符串 或者是一个数字 示例:
<!DOCTYPE HTML>
<h
- java-颠倒一个句子中的词的顺序。比如: I am a student颠倒后变成:student a am I
bylijinnan
java
public class ReverseWords {
/**
* 题目:颠倒一个句子中的词的顺序。比如: I am a student颠倒后变成:student a am I.词以空格分隔。
* 要求:
* 1.实现速度最快,移动最少
* 2.不能使用String的方法如split,indexOf等等。
* 解答:两次翻转。
*/
publ
- web实时通讯
Chen.H
Web浏览器socket脚本
关于web实时通讯,做一些监控软件。
由web服务器组件从消息服务器订阅实时数据,并建立消息服务器到所述web服务器之间的连接,web浏览器利用从所述web服务器下载到web页面的客户端代理与web服务器组件之间的socket连接,建立web浏览器与web服务器之间的持久连接;利用所述客户端代理与web浏览器页面之间的信息交互实现页面本地更新,建立一条从消息服务器到web浏览器页面之间的消息通路
- [基因与生物]远古生物的基因可以嫁接到现代生物基因组中吗?
comsci
生物
大家仅仅把我说的事情当作一个IT行业的笑话来听吧..没有其它更多的意思
如果我们把大自然看成是一位伟大的程序员,专门为地球上的生态系统编制基因代码,并创造出各种不同的生物来,那么6500万年前的程序员开发的代码,是否兼容现代派的程序员的代码和架构呢?
- oracle 外部表
daizj
oracle外部表external tables
oracle外部表是只允许只读访问,不能进行DML操作,不能创建索引,可以对外部表进行的查询,连接,排序,创建视图和创建同义词操作。
you can select, join, or sort external table data. You can also create views and synonyms for external tables. Ho
- aop相关的概念及配置
daysinsun
AOP
切面(Aspect):
通常在目标方法执行前后需要执行的方法(如事务、日志、权限),这些方法我们封装到一个类里面,这个类就叫切面。
连接点(joinpoint)
spring里面的连接点指需要切入的方法,通常这个joinpoint可以作为一个参数传入到切面的方法里面(非常有用的一个东西)。
通知(Advice)
通知就是切面里面方法的具体实现,分为前置、后置、最终、异常环
- 初一上学期难记忆单词背诵第二课
dcj3sjt126com
englishword
middle 中间的,中级的
well 喔,那么;好吧
phone 电话,电话机
policeman 警察
ask 问
take 拿到;带到
address 地址
glad 高兴的,乐意的
why 为什么
China 中国
family 家庭
grandmother (外)祖母
grandfather (外)祖父
wife 妻子
husband 丈夫
da
- Linux日志分析常用命令
dcj3sjt126com
linuxlog
1.查看文件内容
cat
-n 显示行号 2.分页显示
more
Enter 显示下一行
空格 显示下一页
F 显示下一屏
B 显示上一屏
less
/get 查询"get"字符串并高亮显示 3.显示文件尾
tail
-f 不退出持续显示
-n 显示文件最后n行 4.显示头文件
head
-n 显示文件开始n行 5.内容排序
sort
-n 按照
- JSONP 原理分析
fantasy2005
JavaScriptjsonpjsonp 跨域
转自 http://www.nowamagic.net/librarys/veda/detail/224
JavaScript是一种在Web开发中经常使用的前端动态脚本技术。在JavaScript中,有一个很重要的安全性限制,被称为“Same-Origin Policy”(同源策略)。这一策略对于JavaScript代码能够访问的页面内容做了很重要的限制,即JavaScript只能访问与包含它的
- 使用connect by进行级联查询
234390216
oracle查询父子Connect by级联
使用connect by进行级联查询
connect by可以用于级联查询,常用于对具有树状结构的记录查询某一节点的所有子孙节点或所有祖辈节点。
来看一个示例,现假设我们拥有一个菜单表t_menu,其中只有三个字段:
- 一个不错的能将HTML表格导出为excel,pdf等的jquery插件
jackyrong
jquery插件
发现一个老外写的不错的jquery插件,可以实现将HTML
表格导出为excel,pdf等格式,
地址在:
https://github.com/kayalshri/
下面看个例子,实现导出表格到excel,pdf
<html>
<head>
<title>Export html table to excel an
- UI设计中我们为什么需要设计动效
lampcy
UIUI设计
关于Unity3D中的Shader的知识
首先先解释下Unity3D的Shader,Unity里面的Shaders是使用一种叫ShaderLab的语言编写的,它同微软的FX文件或者NVIDIA的CgFX有些类似。传统意义上的vertex shader和pixel shader还是使用标准的Cg/HLSL 编程语言编写的。因此Unity文档里面的Shader,都是指用ShaderLab编写的代码,
- 如何禁止页面缓存
nannan408
htmljspcache
禁止页面使用缓存~
------------------------------------------------
jsp:页面no cache:
response.setHeader("Pragma","No-cache");
response.setHeader("Cache-Control","no-cach
- 以代码的方式管理quartz定时任务的暂停、重启、删除、添加等
Everyday都不同
定时任务管理spring-quartz
【前言】在项目的管理功能中,对定时任务的管理有时会很常见。因为我们不能指望只在配置文件中配置好定时任务就行了,因为如果要控制定时任务的 “暂停” 呢?暂停之后又要在某个时间点 “重启” 该定时任务呢?或者说直接 “删除” 该定时任务呢?要改变某定时任务的触发时间呢? “添加” 一个定时任务对于系统的使用者而言,是不太现实的,因为一个定时任务的处理逻辑他是不
- EXT实例
tntxia
ext
(1) 增加一个按钮
JSP:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
Stri
- 数学学习在计算机研究领域的作用和重要性
xjnine
Math
最近一直有师弟师妹和朋友问我数学和研究的关系,研一要去学什么数学课。毕竟在清华,衡量一个研究生最重要的指标之一就是paper,而没有数学,是肯定上不了世界顶级的期刊和会议的,这在计算机学界尤其重要!你会发现,不论哪个领域有价值的东西,都一定离不开数学!在这样一个信息时代,当google已经让世界没有秘密的时候,一种卓越的数学思维,绝对可以成为你的核心竞争力. 无奈本人实在见地
Comments
只要设计良好,死锁的情况是可以避免的。的确,使用操作系统的多线程同步原语可能会出现死锁的情况,的确,使用 lock-free 在执行效率上更加有优势。但是我要说的是,从目前的情况来看,使用 lock-free 进行编程出现错误的可能性,绝对要比使用同步原语出现死锁的可能性更大,而且我更加认为 lock-free 的代码的可维护性是不会令人满意的。lock-free 目前很不成熟,几乎是不可能用到工程上的。Cloud 自称其资源加载模块运用了该技术,但是就算成功了,这样的代码谁能看懂呢,谁又愿意去维护呢?而操作系统提供的同步原语则是很成熟,并且能够为大多数人接受的。正是因为操作系统对多任务的支持,才简化了我们编程的难度。以目前的情况来看,操作系统的多任务支持和同步原语已经足够满足我们的需求(即便是做游戏开发)。如果一项技术或工具在实现或使用时太过复杂,我想富多人会更加倾向于使用相对简单的,但同样可以解决问题的方法,即便其效率会差一点。而我一直都认为,一个系统越复杂,其出错的可能性就越大,一项技术也是如此。
另外说一下,Windows系统下似乎没有实时线程、内核线程的的概念,Windows中所谓的实时其实是相对的概念,也就是优先级的概念,因为 windows 本身就不具备实时系统的特性。用户模式和内核模式的不同在于访问权限,而与优先权没有太大关系,Windows NT 采用的是微内核架构,即便是驱动程序绝大部分也都是运行在用户模式下。驱动中处理中断的方法和简单,一个事件与中断相关联,一个线程执行一个 while 循环,在循环中 WaitforSingleObject 等待中断事件,如果等到说明中断发生,则进行中断处理。线程阻塞时是不会占用处理器资源的,而所谓的死锁,也不会占用处理器资源,只是死锁的线程永远都处于阻塞状态,而永远都不会有执行的机会。正常下,如果线程中没有死循环和同步原语,线程是可以很快的跑到自己的终点。如果线程有较长的代码执行,他才会占用大量的处理器资源。
Posted by: rockcarry | (49) December 25, 2007 05:43 PM
如果担心自己写的几个线程中,由于某个线程被提升到实时的高优先级关系,而长期霸占 cpu ,导致其它部分的逻辑无法工作。那么就应该使用用户态线程。
在这个问题上,并不是内核线程和用户线程那个优先级高,对系统的控制力强的问题。
区别在于,内核不知道用户逻辑到底在干什么,它的调度方式对用户逻辑是无关。
而把线程调度放在用户态做,可以依赖用户的逻辑来工作。
把多个用户线程塞在一个内核线程里,就无所谓这个内核线程是不是实时的了,也就是让所有用户线程共享同一个内核级别上的线程优先级,而用户自己的代码调度自己的线程,可以控制适的将一条线上的逻辑释放出 CPU 交给另一线的逻辑去工作。
至于 lock-free ,本质上是提供一个不会死锁的并行方案。另外提供了一条思路加快并行工作的效率。它的出现并非是克服 lock 的性能瓶颈的(IMHO)。
Posted by: Cloud | (48) December 18, 2007 04:24 PM
在FreeBSD中,内核线程是分为几类的,例如ithread,可以用于中断处理线程,一般用于软中断,比如在第三层协议栈的处理上,就采用了软中断线程的方式。在网络严重拥挤的情况下,比如用smartbits打压的时候,系统也会出现假死的情况,但这也不是死锁,只是没有足够的时间片用于响应键盘、控制台的IO了。因此内核的进程调度是有足够的强制权的。
在要求实时性高的场合,最好的方式就是尽量少用锁,哪怕是多几个“立交桥”。mp下的锁如同红绿灯,计算小没有关系,计算大就成了瓶颈了。这种情况下就需要很多的经验和技巧了,比如批量处理或将必加锁的时间段相对延长。
而且个人觉得lock-free并不会对MP带来革命性的进步,而且随着MP数的增长,lock-free也会成为瓶颈,除非某一天“局部性原理”被突破或者被绕过去了。
To Cloud:内核如果都没法调度,就不要指望用户层会调度好,用户层的优先级太低了。
Posted by: m | (47) December 18, 2007 03:23 PM
补充一点关于 Windows 的材料,Windows NT 并不提供严格意义上的实时操作系统设施。
参见:Real-Time Systems and Microsoft Windows NT
http://msdn2.microsoft.com/en-us/library/ms810433.aspx
Posted by: Cloud | (46) December 15, 2007 05:42 PM
楼下的提交评论可否改一下不留名的习惯?我不太想改设置完全禁止匿名评论。
江峰的问题是“想以 CAS 方式获得锁”,但是 CAS 本就工作在 lock-free 下况,并非 lock-based 的。根本没有资源被锁住。采用 CAS 的机制也就不会去做 wait-sleep 了。
不管是不是实时线程,全部采用 CAS 机制更新数据,程序都不会有问题。因为要么在处理数据时没有线程切换,CAS 总能成功;要么有线程切换,数据迟早会被正确提交。
至于另一个问题: os 对内核线程的调度。总会有一定机制把低优先级的线程调高,防止饿死。如果担心内核做不到这点(或是强制把线程级设到最高不允许有线程被调整到更高),用用户态线程好了。调度是自己(用户态的库)做的,又有什么好担心的呢?
Posted by: Cloud | (45) December 15, 2007 05:21 PM
to rockcarry & 江峰:
你们最初提到的那个不是 priority inverse 的问题。priority inverse 一般来说要有3个进程互相影响,才算。而且这个问题应该不能算死锁,应该算是活锁……
to cloud & 江峰:
现在的 OS 用的基本上都是 multi-queue 的调度算法,高优先级的队列里面还有进程运行,低优先级的队列里面堆满了进程也不会去运行(广义的来说是这样,实际上不排除有的系统对于多个队列也 round robin 的)。所以对于 Linux 2.6 来说,想让低优先级的运行,低优先级就可以运行,不想让它运行,它就永远在实时线程后面。
to Siney:
这里有一个问题,实时类型的线程的优先级是不会变动的。而其他类型线程优先级会随着运行时间的变化受到调度器的调整(一直跑的程序的优先级会降低)。如果你把线程的优先级调整到实时,那么显然其他的线程都不会响应了……
to m:
Windows XP 的内核是 nonpreemptive 的。如果一个线程在 kernel mode 进行某些耗时很常的行为,那么就会造成响应很差,严重一点就是假死……
关于一开始的江峰提到的那个问题,我认为这个属于设计上的问题。当一个线程无法获取到 lock 的时候,应该采取正确的手段来处理这种情况。不停的尝试去获得一个锁显然是有问题的,kernel 这个时候显然应该应该让这个线程去 sleep,等待唤醒。而一般的 mutex 也是这样干的。对于 spinlock 的话,应该 spin 一会儿然后去 sleep,因为 spinlock 为的是减少不必要的上下文切换。假设在 MP 系统上,A已经占有一个 lock,B 申请这个 lock,但 A 很快就可以释放这个 lock 的情况下,B可以不去 sleep,而直接 spin 一会儿等 A 释放 lock,从而避免了上下文切换。另外要注意的一点是,千万不要让一个获得了 lock 的线程带着 lock 去 sleep,这样很危险,很可能造成死锁。
Posted by: Anonymous | (44) December 15, 2007 04:25 PM
对于linux下的进程调度,个人不认为会允许某一个实时进程始终占据时间这个资源。我对freebsd熟一些。这些开源的系统都会相互借鉴的。对于这些用户层面上的程序,优先级是始终低于内核的响应的。原因在于内核掌控着所有的中断,而这些中断,尤其是硬中断响应级别是非常高的,比如时间、网卡、终端等这些中断响应级别是非常高的。时间片到了,内核进程调度就会根据算法决定下一个进程,进行上下文的切换。
CAS从高级语言这个机器层上来说,就是一个原子操作了,对于CAS不存在死锁。
windows和Linux/freebsd的调度是不同的,所以windows经常会假死掉(尽管从xp后好多了),windows过于放权,导致一些无赖不放手,而且记忆中windows的内核都是通过消息通过各个模块构建起来的,所以不如这些"单核"这么"霸道"。
Posted by: m | (43) December 14, 2007 05:06 PM
我以前也以为系统会自己调度线程,不管线程的优先级高低,总会有机会获得cpu时间,但经过我写程序测试发现(windows),高优先级的程序会妨碍低优先级的程序运行,windows的线程的优先级还有个delta量,系统的会根据delta量再次调节线程的优先级,如果低优先级的经过调节后还是低于高优先级的线程(优先级很高的线程),那么低优先级的线程是永远不会执行的.
可以简单的写个测试程序,比如写个控制台程序,死循环打印一个数,如果你把这个程序的优先级调到很高(通过任务管理器),其他进程都不响应了.
如果调到实时状态,连任务管理器都无法打开.
Posted by: Siney | (42) December 13, 2007 09:49 PM
我想,即使这个线程不会被打断一直跑下去,问题也不会出在死锁上。
因为,这个线程获得 expected 到使用 CAS(v,expected,updated) 更新这个变量之间同样不会被打断。CAS 总是会成功的。除非你混杂用 lock-free 和 lock-based 的策略。
btw, 我还是对这种行为深表怀疑,os 的内核线程调度器会允许一个内核线程永远霸占 CPU ?如果真有 os 允许这样的话,使用用户态线程好了。让用户态的线程库自己利用时钟信号做线程切换。
Posted by: Cloud | (41) December 13, 2007 12:44 AM
TO 云风:
linux2.6中实时进程确实如此。我手头没有权威资料,搜索了一下,找到了这个网页说到了这个:http://pages.cpsc.ucalgary.ca/~madhukar/TA/assignment2.html 当然了,它是否权威难说,但是我确信有这么回事。其中FIFO算法就是协作式的,如果一个采用FIFO调度算法的进程不退出,也没有比它优先级更高的进程,就会一直运行下去。而我们通常情况下的进程都是OTHER这类算法,所以不会有哪个进程永久霸占CPU。里面有这么一段话,这里我copy一下:
A word of caution: Your Linux Shell is using SCHED_OTHER algorithm therefore any Real Time process will take away CPU time from the Shell. This means that Real Time process with an infinite loop in it cannot be stopped! Keep this in mind when experimenting with real time processes.
我认同CAS是原子的,但问题是,在某种情况下,试图用CAS这种方式来保证互斥会导致程序死锁,例如我在四楼所描述的情况。我想知道是我这样的分析是不是对的?如果是对的,那么CAS是怎么用于现实编程的?例如jdk中的concurrency包,我看了一下source code,确实是用了compareAndSwap()。但是我没有往底下看,没功夫。呵呵。
谢谢云风以及各位!
Posted by: 江峰 | (40) December 12, 2007 11:51 PM
to 江峰:
“至少对于linux2.6,如果系统有且只有一个实时进程,那么只要它的进程状态是runnable,那么就会一直跑。”
我不熟悉 linux 不敢妄言,你的意思是说:如果有个线程是 *实时* 的话,它不主动释放时间片就会一直跑下去?
我对此深表怀疑。那样的话,岂不是退回到了 windows 3.1 时代的协作式多线程模式了?
现在大多数 os 都会在时间片用完后把正在运行的线程切出去啊。
另一方面讲,若真是如此,CAS(v,expected,updated) 根本不会失败。因为当前线程获得 expected 到用 CAS 提交 updated 中间没有人打断。
“有且只有一个实时进程”如何定义?如果执行 while(!CAS(v,expected,updated)); 而不用锁的线程就是 *实时* 的,那么工作在 CAS 下的所有线程就都是 *实时* 的了。
关于 CAS 原子性保证的问题,下面我已讨论过,如果 CPU 不提供 CAS 的原子性,我们只需要每个线程把要提交数据利用写操作的原子性写到自己的一个单向队列中。再由一个独立的仲裁线程去原子的读其它所有线程的提交,并给出仲裁结果即可。
Posted by: Cloud | (39) December 12, 2007 12:52 PM
不好意思,这两天有道正式版发布,忘记来这里了,呵呵。顺便也做个广告,去看看有道( http://www.yodao.com/ )。
我提出的问题其实是这样的:抛开gc之类的不说,就说Andrei同学那天讲的CAS的基本原理,是这样的:
while(!CAS(v,expected,updated));
其语意是,如果v等于expected,那么就把updated赋值给v。并且整个CAS原语是由CPU保证的。
顺便说一句,我似乎看到有人在讨论单核读写内存是否是原子操作的问题,Andrei已经讲过了,即便读、写、条件判断是原子操作都没有用。他的原话中文翻译是:“如果给你一个能保证原子赋值操作的CPU你会买吗?”。答案是否定的。
回到正题。我开始的提问是说,想以CAS的方式获得lock的进程是一个“实时”进程。那么云风说的时间片用完的说法就可能不存在了,至少对于linux2.6,如果系统有且只有一个实时进程,那么只要它的进程状态是runnable,那么就会一直跑。退一万步讲,即使会有一些时间片交给普通进程A,可想而知进程A什么时候才能把活干完从而release lock。
这其实也是一种死锁,就是把CPU时间片也当作一个资源来看待。
TO rockcarry:我觉得这不能算是准确的“优先级反转”。优先级反转的关键点在于,低优先级进程反而阻塞了高优先级进程,但低优先级进程是可以run的。而这里不是。这里的情况是等锁的进程是“实时”的,低优先级的进程没有CPU时间片也不能continue。最后造成的结果是,两个进程都不能继续走。
另外,我昨天用java的concurrent包做了一下实验,并不能发现CPU100%的情况。而根据以上推测实时进程不停loop应该是会造成cpu100%的。因此,我觉得Andrei同学漏讲了点什么。或者Andrei同学讲的这个东西本身就是有这个问题,只是jdk做了另外的处理,例如自动转变成了lock-based的调用了。
Any idea?
Posted by: 江峰 | (38) December 12, 2007 11:11 AM
一个资源是这样,但是多个资源就不是了。
比如有两个资源 A 和 B 。大家都是依次处理 A 和 B 。当大家都去抢 A 的时候 lock-free 可以保证先做完的先提交,但传统方法则是谁先请求谁拿到。
如果一个需要很长时间的线程先拿到 A 那么大家都会去等它,而后这个线程要去拿 B ,大家又接着因为 B 去等待。
但是用 lock free 算法,处理 A 快的线程去先完成了,对 B 的处理就被提前了。
当共享资源进一步增加时,lock-free 的效率会更明显。
Posted by: Cloud | (37) December 10, 2007 05:01 PM
cowboy的说法正确 呵呵 撤消重做的代价太大了,在对共享资源有更新处理时候, 只要单个线程对资源的处理时间大于两次处理之间的间隔时间,那么在多个线程处理情况下重做总是会发生.
对于n个同步启动的处理相同的线程,即使不考虑优胜线程再次加入竞争, 重做次数也至少是n!-n. 最后一个线程在最理想的情况下完成第一次处理的时间点也是n*t了,与带lock模式相比总体效率无提高,但是总体cpu消耗就大的不可以道理计了
至于说避免死锁也不是lookfree的优势,死锁是可以由流程设计上去避免的,反而我觉得,只要从设计上去提高并行度尽量降低锁内处理,锁结构的运行性能是完全可以稳定估量的,而lockfree结构则在运行态上是不稳定的,存在性能风险.
Posted by: Anonymous | (36) December 10, 2007 04:32 PM
我认为 Bit Cowboy 的说法过于武断,不知道“这个说法是有实验数据支撑的”有没有具体参考。
Lock-free 有一定的性能损失,这个我在下面 26 楼简单分析过。
但是要说随着核的增加,性能损失会越来越大,我不赞同。
当很多线程同时更新同一资源时,如果是依赖锁还是免锁,由于工作必须串行化,所用的时候都不会超过单线程串行处理。
lock-free 的性能损失在于一个任务完成后,其它任务正在重做上次会被作废掉的事情,导致一小段的空闲时间。
但是随着并发任务增加,总是最快的那个线程正确提交结果。性能损失会随着核的增加而趋于稳定。
另一方面,随着事务的复杂,lock-free 天生总能让同时请求同一资源的多个线程中做的最快的那个先完成。这比传统的锁依赖算法是个很大的改进。很有可能改进总体性能。
这就好比大家排队打水,让桶小的人排在前面,可以使大家总等待时间变短。如果只有打水一件事,总时间不会因为改变次序而改变。但是除了打水,还有排队买饭等等别的事情时,让做的快的人插队先做,却可以让集体的总时间缩短。
ps. 虽然没有死锁问题,但是在极端情况下,lock-free 的算法有可能导致几个工作的慢的线程永远提交不了数据。(比如同时有别的核不间断的高频修改同一资源)这时候就依赖于 os 把高频的线程挂起一小段时间了。
Posted by: Cloud | (35) December 10, 2007 02:12 PM
Lock-free算法的可扩展性是很差的。当同时并行执行的线程越多(CPU硬件核心越多)的情况下,性能越差,并且无限接近单线程的性能。这个说法是有实验数据支撑的。原因是因为,Lock-free是一个“乐观锁”,它假设冲突不会发生,而等到真的发生了冲突再去修正(撤销数据提交重做)。而当并行执行的线程越多,它们之间的冲突也是以N^2被增长的。所以大量的CPU时间都被浪费在数据重做上。大家有兴趣可以参考“事务式内存”方面的资料。
Lock-free算法在8核一下的情况下效率还是不错了,超过8核,效率就比较低了。Lock-free的最大价值在于,它不会有死锁,而且,目前状况下性能够用。
如果要用好像Intel 80核那样的CPU,数据上的并行考虑是必须的。
Posted by: Bit Cowboy | (34) December 10, 2007 11:46 AM
换个标准点的阅读器吧,“新浪点点通" 肯定不标准。
那个链接不是文章链接。而且 atom 文件中已经写明了是 link rel="service.edit" type="application/atom+xml"
这个链接是 atom 协议中用于修改和发布的。普通用户不应该看的见。而且链接直接访问也会因为通不过认证而失败。
ps. 但是还是把缺少的 SHA1 模块装上了。
Posted by: Cloud | (33) December 10, 2007 12:32 AM
续上:FEEDS地址:
http://blog.codingnow.com/atom.xml
Posted by: Ninstein | (32) December 9, 2007 11:12 PM
To Cloud:
很早就发现这个问题了
新浪点点通
如此文在阅读器中文章链接为:
http://blog.codingnow.com/mt/mt-atom.cgi/weblog/blog_id=1/entry_id=317
现在点击提示:
Got an error: Can't locate Digest/SHA1.pm in @INC (@INC contains: /var/www/mt/extlib lib /etc/perl /usr/local/lib/perl/5.8.4 /usr/local/share/perl/5.8.4 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.8 /usr/share/perl/5.8 /usr/local/lib/site_perl .) at lib/MT/AtomServer.pm line 14.
BEGIN failed--compilation aborted at lib/MT/AtomServer.pm line 14.
Compilation failed in require at (eval 2) line 1.
Posted by: Ninstein | (31) December 9, 2007 11:10 PM
C 的 expat 模块以及 perl 的XML::Parser 模块没有安装,刚才都去装上了。
为啥一直没有人提呢?我用 MT 确省设置装的 blog 系统,没精力折腾。
另外,哪些出错信息怎么出来的?为啥我用 opera 订阅和 google reader 订阅都没问题?
Posted by: Cloud | (30) December 9, 2007 06:47 PM
云风大哥,你BLOG的RSS能不能调一下,订阅后点链接提示:
Got an error: Can't locate XML/Parser.pm in @INC (@INC contains: /var/www/mt/extlib lib /etc/perl /usr/local/lib/perl/5.8.4 /usr/local/share/perl/5.8.4 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.8 /usr/share/perl/5.8 /usr/local/lib/site_perl .) at /var/www/mt/extlib/XML/XPath/XMLParser.pm line 7.
BEGIN failed--compilation aborted at /var/www/mt/extlib/XML/XPath/XMLParser.pm line 7.
Compilation failed in require at /var/www/mt/extlib/XML/XPath.pm line 13.
BEGIN failed--compilation aborted at /var/www/mt/extlib/XML/XPath.pm line 13.
Compilation failed in require at /var/www/mt/extlib/XML/Atom.pm line 11.
BEGIN failed--compilation aborted at /var/www/mt/extlib/XML/Atom.pm line 24.
Compilation failed in require at lib/MT/AtomServer.pm line 10.
BEGIN failed--compilation aborted at lib/MT/AtomServer.pm line 10.
Compilation failed in require at (eval 2) line 1.
或者干脆将简报内容字数调大些,方便那些通过阅读器订阅你博客的网友阅览。
Posted by: Ninstein | (29) December 9, 2007 03:22 PM
从字义上讲,无锁是对lock-free的误解。如果没有接触过lock-free,见到无锁的第一印象,是没有涉及到锁的技术。
Posted by: Anonymous | (28) December 7, 2007 04:24 PM
应用层上,稳定性是高于性能的,但是在内核层上,性能是同等于稳定的。
Posted by: Anonymous | (27) December 7, 2007 04:19 PM
lock-free 的本质是:大家把事情尽量的按自己的流程做,做错了再重做。不要相互等待,如果 A 和 B 同时依赖一个资源,那么让 A , B 同时去做,然后只取一个结果,让另一个重来一次。它并不提高效率,当 A,B 同时开始时,完成 A 和 B 两项工作的总体时间是 2 * max (A,B) 。
而依赖锁的方法本质上是让 A 事情做完了 B 再继续,需要的时间是 A+B 。至于花在锁本身上的时间是几乎忽略不计的。
lock-free 最终解决的问题是,保证正确的基础上,降低实现的复杂度。它最大的功劳是杜绝了逻辑上的死锁。
所以对于 lock-free 最后的原子操作怎么实现,并不重要。
即使 CAS 以来硬件保证的一个最小粒度的锁来保证原子操作,lock-free 的思考方式也现在以来资源锁这种也不同的。因为这个原子操作永远不会有逻辑上死锁的问题。编程上也可以减少更多的失误。
至于 lock-free 在 C/C++ 层面实现的复杂度,更多的是没有 gc 机制带来的,而不是方法本身。
ps. 昨天贴的一个用单独线程来取代 CAS 中比较交换的原子操作的方法,今天再想想还有一些性能问题。主要是还需要做一些改进让仲裁线程不被阻塞。整个方案实际上是用一个单独线程来保证 CAS 需要的原子操作,但代价反而更大 :(
Posted by: Cloud | (26) December 7, 2007 02:42 PM
许多时候在工程上看重得更多的是稳定性,而不是性能,即便是做游戏开发也是如此。如果要我选择,我还是使用操作系统提供的 API 来对临界资源进行保护。在工程上都是使用成熟的技术来保证稳定性和缩短开发周期。
Posted by: rockcarry | (25) December 7, 2007 10:08 AM
赞同 Cowboy
这样说来软件的架构设计上还是很关键的,在设计上尽量避免多个线程共享数据,尽量避免锁的使用。
lock-free 很好,可惜实现起来太复杂了,而且可移植性不好,因为这个跟处理器和编译器的细节有太大的关系。要真正的应用还是困难。
Posted by: Anonymous | (24) December 7, 2007 09:50 AM
云风:
Csdn 博客系统有哪些问题,你可以提点意见,我们正打算做新系统。By the way,评论不允许超过250字,是不是因为这个原因你发不出去评论?
Posted by: 张英刚 | (23) December 7, 2007 09:10 AM
不管是操作系统锁、还是CPU硬件锁。锁的目的就是让程序不能并行运行。不管用什么样的锁,只要大量使用都会让多核的应用退回到单核状态。
并行计算的关键不在于锁,而在于在一个系统架构设计的时候就考虑到将数据最大限度的分离开,使得各个线程在运行的时候可以不访问或者很少访问共享的变量或者数据结构才可能真正让程序并行跑起来。
Lock-free不过是对锁的一个改进,但是并不是包治并行程序设计百病的灵丹妙药。
Posted by: Bit Cowboy | (22) December 7, 2007 09:06 AM
今天想了一下,然后又跟同事讨论了一会儿。如果未来核特别多的话,如果可以拿出一个核,倒是可以只用读写原子操作模拟出 CAS 来。
方法是这样的:
首先看一个更简单的问题:队列操作。如果对一个队列只有一个 thread 有写权限(进入队列),其它 thread 都只有读权限。那么,只需要读写操作原子即可保证安全。
如果有多个 thread 都需要写队列,我们可以这样做:让每个 thread 把数据分别写到自己的队列中,然后用一个单独的队列不断的去搜集所有工作 thread 的私有队列信息,合并起来。
因为合并之后的队列也只有一个 thread 对其写,而其它队列仅仅是读,那么依旧是安全的。
再来看 CAS 。如果每个可能被修改的数据单元为每个 thread 分配一个子单元(这些单元可以用链表串起来),那么每个 thread 修改这个数据单元都互不影响。它们均把老的值和新的值写入。
然后另外开一个额外的 thread 专门做仲裁。仲裁者从各个 thread 写入的数据中挑出合法的版本,放到最终的结果中。之后,每个工作 thread 再检查最终结果是否是自己来决定是否继续尝试。成功后再将结果设置为过期,让仲裁 thread 继续工作。
大概的想法就是这样啊,没有仔细再想下去,我觉得还是可行的。不过现在肯定没有实用价值。
Posted by: Cloud | (21) December 6, 2007 08:15 PM
关于InterlockedIncrement是否多余。
在32位x86平台下写一个DWORD确实是原子操作了,不管有多少的核心都一样,这个是Intel自己说的。但是InterlockedIncrement做的是+=1操作,不是简单的赋值操作。+=1怎么实现?是先把原来的值从内存里读出来,然后做加一运算,最后再写回到内存里去,是三步操作完成的。三条CPU指令怎么可能原子操作呢。如何保证在做+1操作的时候别的CPU核没有改变那块内存的值呢?这三条指令别说是多核了,就算是在单核心多线程的情况下都不能保证原子操作。
所以Intel引入了CAS指令,用一条硬件指令来做三个操作。这样可以保证这条指令在操作是时候线程不会被操作系统时间片调度程序打断。
不过,在多核时代,仅仅这样的保证就不够了。因为有并行(不是并发)的线程在执行。所以Intel又提供了lock指令前缀。在CAS指令前面加上lock前缀,可以在执行这条指令的同时调用CPU的Cache一致性模型来保证多个内核看见和操作的是同一块实际内存的值而不是各自Cache里的值(如果多个核心不是共享Cache的话),并且通过锁顶内存地址线的方式(这个是比较老的方法了,不知道Intel的Core架构上有没有改进)强制同一时间只有一个CPU核可以写那块内存,从而保证了多核情况下的线程安全操作。从这里可以看出,“锁”实际上被移到了CPU内部,由硬件高效得来完成。
另一个保证线程安全的前提可能更容易被大家忽略。大家如果用过InterlockedIncrement接口的话应该就会发现,这个接口要求的操作变量必须是被volatile修饰的。volatile这个修饰符的意义在于,告诉编译器,不要把对这个内存块的操作优化成寄存器操作。通常情况加,为了加速变量的操作,编译器会自己把一组的变量操作优化成在CPU内部寄存器里运算,而不是立即写回内存的。但是,我们从前面的分析就可以知道,CPU的lock CAS操作是对内存的线程安全保证,并不能对CPU内部的寄存器里的值做任何保证。本来吗,寄存器就是各个CPU核心私有的,对不对。
所以lock CAS和volatile是两个基本条件确一不可。
看到有人在问学习Lock-free算法的资料,这方面系统的学习资料好像不多。我觉得可以从两个方面,一个是看Intel的汇编指令,不过这个枯燥了一点,也没有什么效率。另一个是看源代码。Windows里的Interlocked系列函数其实已经包含了不少Lock free算法的实现了,不过它最大的问题是不能跨平台,而且也没有公开源代码。不过要看Interlocked系列函数的实现还是可以的,Interlocked系列函数是用户空间的函数,不用切换到内核去执行,所以,其实可以在VC里面通过反汇编看他的汇编实现。如果你就是怕看汇编的话,那么我向你推荐一个好东西,apache项目的APR,apache protable runtime,是apache项目自己做的一个跨平台库,其中包含了很多Lock free算法的实现,而且是跨平台的,而且,最重要的是,提供了源代码。有兴趣的话可以从APR的原子操作开始学习。
Posted by: Bit Cowboy | (20) December 6, 2007 07:12 PM
看了下 lock-free 和 CAS, 我的确理解错了,抱歉。觉得这个真的很神奇,太不可思议了。
但是目前要应用还是很难啊。
Posted by: rockcarry | (19) December 6, 2007 06:20 PM
Anonymous正解
既然要同步,就一定要上锁。Lock-free还是要上锁啊,只是影响面缩小了。
那个谁rockcarry,WaitForSingleObject一类的API在这里不适用,大伙是在讨论LOCK-FREE不是WINDOWS自带的各种同步对象别搞错了。。
大伙继续。
Posted by: Rome | (18) December 6, 2007 05:52 PM
看了下,CAS这个操作有点神奇,看来我可能想错了。
Posted by: Anonymous | (17) December 6, 2007 05:34 PM
再次看了下资料 lock-free 的概念似乎仅仅适用于多核处理器的系统中。网上有许多文章在谈论这个,似乎是在滥用概念。当然,我也是才听说这个,不能确定,还需要继续找资料看看。
Posted by: rockcarry | (16) December 6, 2007 05:21 PM
CAS 本质上是给对象赋予了一个版本号,而版本号这个东西用一个字长足够了。
Posted by: Cloud | (15) December 6, 2007 05:01 PM
就算单个的内存访问是原子操作,实现 lock-free 的库也很困难。因为一个对象内部不可能只用一个内存单元来存放数据。因此,lock-free 的东西,在目前的处理器架构上很难实现。目前仍然需要借助多任务的操作系统。lock-free 只有等待新的处理器架构的出现,
Posted by: rockcarry | (14) December 6, 2007 03:03 PM
至于大家所提的 lock-free 的东西,目前还只是处于研究的初级阶段,根本谈不上应用,也不是我们搞工程的需要研究的。
Posted by: rockcarry | (13) December 6, 2007 02:51 PM
单核时,有些操作,比如写内存,本身就是原子的。不需要用 lock 前缀。所以可以构造一些数据结构,完成一些有限的事情,而不用 cmpxchg 这样的操作。
比如只有一个线程在一个单项链表后追加数据,而另外的线程只用来读。那么这样的数据结构就可以不用锁来完成。
我们的资源加载模块就基于这个完成的:
http://blog.codingnow.com/2007/05/mutilthread_preload.html
Posted by: Cloud | (12) December 6, 2007 02:51 PM
不知道大家所提的锁到底是个什么东西,据我所知,在 Windows 平台上进行多线程编程时,线程之间同步的方法很多 Event, Mutex, Semaphore, CriticalSection, 等等内核对象,足够满足我们的需求,我们可以根据需要具体选用。加锁是为了在多访问时对临界资源进行保护,这可以通过 Mutex 或者 CriticalSection 来实现,但这仅仅是多任务同步中的一个方面。许多多任务的同步是不需要加锁的,比如说某个线程要等待某个事件的发生(这时需要用到 Event 或 Semaphore)。
在多任务系统之上,所有的多任务操作,都是由操作系统和操作系统提供的 API 来管理和实现,这与具体的机器指令无关。操作系统通过内核对象来实现多任务同步和临界资源的管理,这样的实现,也不需要处理器提供特别的指令支持。
而大家所提的 CPU 的总线的 lock 信号,和相应的 lock 指令其实跟这个关系不大。在单核的系统上,能够与总线和主存打交道的器件,估计也就只有 DMA 控制器和 CPU 了,当 CPU LOCK 了总线以后,其他要使用总线的器件都必须等待总线的释放。因此说,在单核处理器中 LOCK 指令时没有什么用武之地的。但是 LOCK 指令在多核的系统中是极为重要的,而且是必需的,再多核的系统中,访问内存,必须要使用 LOCK 指令来锁住总线,然后处理器再在总线上产生读写的控制信号,所谓总线和控制信号的概念,大家应该都清楚吧。如果不 LOCK 的话,两个 CPU 都在同时往总线上放控制信号,岂不是乱套了,这必然会导致主存的访问出错。
因此说 LOCK 在多核处理器架构的系统上是必需的,然而这个东西似乎与我们通常所说的多任务同步等等问题没有关系。就算有关系,也都是由支持多核的操作系统和编译器去处理掉了,在操作系统之上,我们看到的是一个虚拟机,不用也没有必要去关心底层的实现细节。
Posted by: rockcarry | (11) December 6, 2007 02:30 PM
单核多线程,不加锁,不能做到同步吧?
所谓的无锁,其实也不是真正的无锁,只不过是将巨锁(相对的),变成了单条指令锁,Andrei讲到的CAS,换成机器指令为 lock cmpxchg。指令前缀lock还是排他的。基于lock-free的库,大家也可以在网上找得到。
Posted by: Anonymous | (10) December 6, 2007 01:21 PM
江峰所提的似乎是实时系统中优先级反转的问题,在实时系统中,这个问题已经有解决办法,可以参考相关资料。
另外提一点,多任务的系统中,一个任务如果得不到临界资源,操作系统会将该任务变为阻塞状态,该任务不会占用处理器资源,而持有临界资源的任务仍然会继续运行,直到新的任务调度产生。
至于你所说的“不停的 while-loop”我不太明白是什么意思。如果是等待临界资源,操作系统一般都会提供相关的 API, 比如 Win32 API 的 WaitForSingleObject。
Posted by: rockcarry | (9) December 6, 2007 12:44 PM
Andrei 想说的死锁应该是指:线程对资源的循环依赖。
A 线程依次请求 1,2 资源;B 线程依次请求 2,1 资源。一旦 A 申请到了 1 ,B 申请到了 2 ,大家都在请求下一个资源时就会发生死锁。
Posted by: Cloud | (8) December 6, 2007 12:17 PM
to 周伟民,我依稀记得有个类似 ReadBarrier WriteBarrier 的 API 可以干这事。不知道是 Windows 提供的还是啥库提供的。不过用最新版本的 Intel C / gcc / VC 的话,对应的 api 是 _mm_lfence() _mm_sfence()
我这两年都没用 Windows 系统的,Interlocked* 系列的 api 细节不太清楚。
to 江峰,
那样不会死锁的,因为 os 会在每个线程的时间片耗尽时切换出去。
为了防止低优先级的线程锁住资源,而高优先级的线程相互轮占 cpu ,导致死锁,os 通常会按一定的机制自动调整优先级别,让每个线程都有机会活动。
Windows 下的线程调度,推荐阅读:《深入解析 Windows 操作系统第 4 版》6.5 线程调度。
Posted by: Cloud | (7) December 6, 2007 12:13 PM
to 江峰 :
不是实时系统的话.任务管理系统会给A分配时间片的吧.
Posted by: error.d | (6) December 6, 2007 11:45 AM
spin-lock 貌似问题多多啊,主要是在cpu资源的分配和多路同写的重复操作上,正如下面tx说的,假如有个THREAD_PRIORITY_HIGHEST的线程与另一个THREAD_PRIORITY_LOWEST甚至THREAD_PRIORITY_IDLE之间存在spinlock的关联,那么很可能死锁,至少效率会无比低下.
Posted by: Anonymous | (5) December 6, 2007 11:31 AM
云风,你好。我是有道的。我当时问了Andrei一个问题,就是:假设有两个进程A和B,进程A已经获得了lock,并且正在做他的事情。这时候一个实时进程B想要获得这个lock,于是就在不断的while-loop,而进程A却得不到CPU时间片去完成他的事情。于是便发生了死锁。是不是这样?当然我没有想清楚,就被Andrei同学糊弄过去了。呵呵。
Posted by: 江峰 | (4) December 6, 2007 11:06 AM
麻烦云风兄给推荐一个多核开发的入门书籍
谢
Posted by: 知名不具 | (3) December 6, 2007 10:22 AM
多谢云风讲fence指令的这篇文章,不过还有一个问题没有解决,
那就是InterlockedIncrementAcquire()和InterlockedIncrementRelease()是不是用sfence和lfence指令实现的?
毕竟编程的时候不可能直接去使用这种底层的指令吧?
Posted by: 周伟明 | (2) December 6, 2007 09:03 AM
很艰难的看完了..发现还是没看懂..哎.不是写游戏引擎的,真的是没考虑计算机底层的那么多东西...先干好我的逻辑程序员吧- -!
Posted by: WJY | (1) December 6, 2007 08:47 AM