多线程开发是一件需要特别精心的事情,即使是对有多年开发经验的工程师来说。
为了能让初级开发工程师也能使用多线程,同时还要简化复杂性。各种编程工具提供了各自的办法。对于iOS来说,建议在尽可能的情况下避免直接操作线程,使用比如NSOperationQueue这样的机制。
可以把NSOperationQueue看作一个线程池,可往线程池中添加操作(NSOperation)到队列中。线程池中的线程可看作消费者,从队列中取走操作,并执行它。
你可以设置线程池中只有一个线程,这样,各个操作就可以认为是近似的顺序执行了。为什么说是近似呢,后面会做解释。
编写最简单的示例
先写个最简单的示例。
编写一个NSOperation的子类,只需实现main方法。这里非常类似Java的Thread,你可以继承它,并覆盖run方法,在该方法里面写入需要执行的代码。这里的main方法和run方法作用是相似的。
头文件:
这里的operationId属性不是必须的,是我想在后面标识区分多个Task的标识位。
m文件:
这里模拟了一个耗时10秒钟的操作。
下面需要把Task加入到队列中:
我直接找了个Controller的方法写上了。运行结果是,界面出现了,而task还未执行完,说明是多线程的。10秒钟后,日志打印完毕,类似这样:
2011-07-18 15:59:24.623 MultiThreadTest[24271:6103] task 1 is finished.
可以向操作队列(NSOperationQueue)增加多个操作,比如这样:
那么打印出的内容是不定的,有可能是这样:
2011-07-18 15:49:48.087 MultiThreadTest[24139:1903] task 2 run …
2011-07-18 15:49:58.122 MultiThreadTest[24139:6203] task 1 is finished.
2011-07-18 15:49:58.122 MultiThreadTest[24139:1903] task 2 is finished.
甚至有可能是这样:
2011-07-18 15:52:24.685 MultiThreadTest[24168:6003] task 1 run …
2011-07-18 15:52:34.708 MultiThreadTest[24168:1b03] task 2 is finished.
2011-07-18 15:52:34.708 MultiThreadTest[24168:6003] task 1 is finished.
因为两个操作提交的时间间隔很近,线程池中的线程,谁先启动是不定的。
那么,如果需要严格意义的顺序执行,怎么办呢?
处理操作之间的依赖关系
如果操作直接有依赖关系,比如第二个操作必须等第一个操作结束后再执行,需要这样写:
这样,即使是多线程情况下,可以看到操作是严格按照先后次序执行的。
控制线程池中的线程数
可以通过类似下面的代码:
来设置线程池中的线程数,也就是并发操作数。默认情况下是-1,也就是没有限制,同时运行队列中的全部操作。
转自:http://www.codeios.com/thread-1688-1-1.html
=====================
自己的感悟:
1. 如果在某个operation完成以后,可能需要回调。在多个线程同时开启的状态下,需要考虑synchronize的问题
2. ...
2011年最后一篇。。。。
上一篇中的代码最好需要优化,特别对字库文件需要优化。股票成千上万个,如何做到快速匹配是很值得研究的。
写了一个转换函数,将类似4E48 (me5,ma5,yao1)的文本转换成4E48 (m,y),代码如下:
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class TestMain { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub final String fromName = "e:\\unicode_to_hanyu_pinyin.txt"; final String toName = "e:\\unicode_to_simple_pinyin.txt"; TestMain t=new TestMain(); t.convert(fromName,toName); } public void convert(String fromFile,String toFile) { try { BufferedWriter writer = new BufferedWriter(new FileWriter(new File(toFile))); BufferedReader reader = new BufferedReader(new FileReader(new File(fromFile))); String tempString = null; int line = 1; while ((tempString = reader.readLine()) != null) { // 显示行号 String pre=getPre(tempString);//获得“(”前面部分 String[] t=getMiddle(tempString);// String s=""; for(int i=0;i<t.length;i++){ String sub=t[i].substring(0, 1); if(i+1<t.length){//去掉重复项 String sub2=t[i+1].substring(0, 1); if(sub.equals(sub2)){ continue; } } s+=","+sub; } s=pre+s.substring(1)+")"; writer.write(s); writer.newLine(); line++; } reader.close(); writer.close(); } catch (IOException e) { e.printStackTrace(); } } private String getPre(String pinyinRecord){ int indexOfLeftBracket = pinyinRecord.indexOf("(")+1; String stripedString = pinyinRecord.substring(0,indexOfLeftBracket); return stripedString; } private String[] getMiddle(String pinyinRecord){ int left= pinyinRecord.indexOf("("); int right= pinyinRecord.lastIndexOf(")"); String middle = pinyinRecord.substring(left+ "(".length(), right); return middle.split(","); } }
修改PinYin4j.java:
package com.ql.util; import java.util.Arrays; import java.util.HashSet; import java.util.Set; public class PinYin4j { public PinYin4j(){ } /** * 字符串集合转换字符串(逗号分隔),测试用 * * @param stringSet * @return */ public String makeStringByStringSet(Set<String> stringSet) { StringBuilder str = new StringBuilder(); int i = 0; for (String s : stringSet) { if (i == stringSet.size() - 1) { str.append(s); } else { str.append(s + ","); } i++; } return str.toString().toLowerCase(); } /** * 获取拼音集合 * * @author wyh * @param src * @return Set<String> */ public Set<String> getPinyin(String src) { char[] srcChar; srcChar = src.toCharArray(); //1:多少个汉字 //2:每个汉字多少种读音 String[][] temp = new String[src.length()][]; for (int i = 0; i < srcChar.length; i++) { char c = srcChar[i]; // 是中文或者a-z或者A-Z转换拼音(我的需求,是保留中文或者a-z或者A-Z) if (String.valueOf(c).matches("[\\u4E00-\\u9FA5]+")) {//中文 String[] t = PinyinHelper.getUnformattedHanyuPinyinStringArray(c); temp[i] = new String[t.length]; for(int j=0;j<t.length;j++){ // temp[i][j]=t[j].substring(0,1);//获取首字母 temp[i][j]=t[j];//获取首字母,不需要再截取了 } } else if (((int) c >= 65 && (int) c <= 90) || ((int) c >= 97 && (int) c <= 122) ||c>=48&&c<=57||c==42) {//a-zA-Z0-9* temp[i] = new String[] { String.valueOf(srcChar[i]) }; } else { temp[i] = new String[] {"null!"}; } } return paiLie(temp);//直接返回Set } /* * 求2维数组所有排列组合情况 * 比如:{{1,2},{3},{4},{5,6}}共有2中排列,为:1345,1346,2345,2346 */ private Set<String> paiLie(String[][] str){ int max=1; for(int i=0;i<str.length;i++){ max*=str[i].length; } Set<String> result=new HashSet<String>(); for(int i = 0; i < max; i++){ String s = ""; int temp = 1; //注意这个temp的用法。 for(int j = 0; j < str.length; j++){ temp *= str[j].length; s += str[j][i / (max / temp) % str[j].length]; } result.add(s); } return result; } /** * @param args */ public static void main(String[] args) { //nongyeyinheng,nongyeyinhang,nongyeyinxing PinYin4j t=new PinYin4j(); String str = "农业银行1234567890abcdefghijklmnopqrstuvwxyz*"; System.out.println(t.makeStringByStringSet(t.getPinyin(str))); } }
其他地方可以保持不变。
最后,采用AutoCompleteTextView做出来的提示很丑,漂亮一点的看下图,这可不是AutoCompleteTextView做的哦。
想做这样的效果吗。
除非你现在正处在世外桃源,否则你不可能没有听说过web设计者间最近广泛流行的响应设计(Responsive Design)。Ethan Marcotte使用responsive design这一术语描述一种新兴的技术,它采用易变的布局和媒体查询扩展网站,使得网站能够动态适应各种尺寸大小的屏幕。如果你之前从未听说过响应设计,那么你可以好好读读Marcotte的介绍文章。
简而言之,响应设计就是使用非固定的网格、非固定的布局和@多媒体查询使得现在的(以及将来的)web能够适应不同尺寸的屏幕。无论你的用户使用的是一个电话,一个iPad或是巨大的台式显示器,你的网站都能够适应。
响应设计将成为一个非常有吸引力的工具,正如Luke Wroblewski所说的,设计需要遵循移动优先原则。也就是,从小屏幕开始考虑。先理清你的网站的核心,然后一点点开始构建。从骨架开始构建能够保证网站的质量,促使开发人员关注用户所关注的问题。
你打算如何构建一个响应良好的网站呢?这个问题因人而异,但是还是存在一些通用的方法的。为了帮助你开始响应设计,这里列出了一些初期设计时的最好实践经验,都是从大量的web资源中总结出来的:
- 使用@media控制你的屏幕布局,但是需要记住,只有这些并不是一个真正的响应设计。
- 使用非固定的布局适应各种屏幕的尺寸。不要将你的设计限制在iPhone或是Android上,不要将它切割为平板电脑版本和桌面电脑版本。布局设计需要更加灵活可变,否则,如果某个新的屏幕尺寸突然变成潮流,你的网站将无法应对。
- 根据你的网站的具体内容设定你的网格。封装好的网格系统可能并不适用于你的应用。这类网格的最大问题就是它们可能与你的具体内容不符。根据网站内容设计你的布局,而不是根据canvas(或是网格)。
- 从小屏幕开始。从最新的屏幕开始设计,然后逐步在浮动元素中加入@media规则,满足更大的平板或是桌面浏览器的窗口需要。从一个窄的单列布局开始设计移动浏览器网站,然后再逐步扩大。
- 使用Respond或是CSS3 Media Queries这类JavaScript库引导@media查询,因为在旧版本的浏览器中可能不支持直接的@media查询。从最小的屏幕开始然后逐步扩大意味着,桌面浏览器需要处理@media,确保使用Respond这类辅助工具能够支持旧版本的浏览器处理@media。
- 不要指望Photoshop,在浏览器中构建你的组件。使用Photoshop构建动态的布局压根就没有可能性,应该在浏览器中实现。
- 使用img { max-width: 100%; }控制图像大小。对于大规模的图像,可以考虑在小屏幕中使用Responsive Images这类工具缩小图像的大小,然后在大屏幕中使用JavaScript还原大图像。
- 延迟下载。可能你的网站中有些辅助元素,能够优化你的网站,但并不是必须的。这类元素可以在下载完基本内容后再使用JavaScript加载这些元素。
- 不用处处要求完美。即使做到了上述建议,你可能还是会漏掉某些使用不支持JavaScript的旧版本浏览器的用户。现在这样的用户已经越来越少了,如果他们在桌面浏览器中看到了移动版本的布局,这也并不就是世界末日。你的网站已经具备很好的可用性了。
记住响应设计是一个非常年轻的概念——是一个新的工具——每天都会涌现出一些新的东西。不要将上面的建议当做是一些硬性或是速成的规则,它只是一些引导指南罢了。
文章来源:Tips, Tricks and Best Practices for Responsive Design
译文来源:http://www.webapptrend.com/
WebAppTrend是一个独立的技术博客,关注Web App前瞻和实践,以及智能浏览器发展
请大家在关注ITeye的同时,关注我们的新浪微博 @WebAppTrend,关注我们的腾讯微博@WebAppTrend,欢迎加入我们的Q Q群:193775364