首页 文章 精选 留言 我的

精选列表

搜索[镜像无法拉取],共10000篇文章
优秀的个人博客,低调大师

踏破铁鞋觅处,从AsyncTask学Android线程池

android对于主线程的响应时间限制的非常严格,稍有不慎就会遇到Application Not Responding(ANR)的弹框。用户可以轻点手指关掉你的APP。官方文档写的非常明确!同时,保持应用随时响应用户的操作也是良好用户体验的前提。 线程的开始和结束 要做到以上多线程是必不可少的。课本会告诉你什么时候开辟一个线程,但是很少说的一个很重要的问题是结束。比如,我现在在Activity里有一个工作需要创建一个线程执行,但是这个Activity在进入后台后不幸遇到系统回收资源被销毁了。但是这个线程还在漫无目的的游走,耗费资源。 如何结束?先创建一个: mThread = Thread(Runnable { // do something here... }) mThread?.start() 以上使用kotlin的lambda表达式简写了创建Runnable对象部分的代码。主旨还是创建了一个Runnable对象,并将其作为参数传入Thread。 如何让一个Thread能够退出呢?这就要在Runnable身上下功夫了。首先添加一个是否停止的标识isCancelled,一旦值为true则停止线程的运行,否则继续。我们这里不讨论Thread#interrupt()这个方法,这个方法诡异的地方太多。 首先要给Runnable“添加一个属性”作为上文的是否停止的标识。直接添加时不可能的,Runnable只是一个interface,不是class。所以要实现这个借口为一个抽象类,这样就可以添加属性了。 abstract class CancelableRunnable() : Runnable { var isCancelled: Boolean = false } 这里使用抽象类,是因为run()方法的实现留给使用的时候给出。 var runnable = object : CancelableRunnable() { override fun run() { if (isCancelled) { var msg = mHandler.obtainMessage(THREAD_CANCELLED) mHandler.sendMessage(msg) return } Thread.sleep(2000) if (isCancelled) { var msg = mHandler.obtainMessage(THREAD_CANCELLED) mHandler.sendMessage(msg) return } var msg = mHandler.obtainMessage(THREAD_FINISHED) mHandler.sendMessage(msg) } } Thread.sleep(2000)用来模拟一个费时的任务。开始之前检测是否取消了线程的执行,执行之后在检测。之后的检测是有的时候任务执行之后需要有持久化处理结果或者修改任务完成情况的标识之类的动作,如果已经取消了线程的执行,即使任务执行完成也不持久化结果、不修改完成情况。 最后都检测完成之后如果没有取消线程,则发出任务完成执行的消息。 发出和处理这些消息的Handler的定义: var mHandler = object : Handler() { override fun handleMessage(msg: Message?) { when (msg?.what) { THREAD_CANCELLED -> { mResultTextView.text = "thread cancelled" } THREAD_FINISHED -> { mResultTextView.text = "thread finished" } else -> { mResultTextView.text = "what's going on" } } } } 运行在UI线程的Handler检测从线程发出的消息,如果是THREAD_CANCELLED那就是线程已经取消了,如果是THREAD_FINISHED那就是线程完全运行结束。之后根据message的消息设置TextView的文本内容。 这里使用了两个按钮来启动和停止线程: findViewById(R.id.start_button)?.setOnClickListener { v -> runnable.isCancelled = false mThread = Thread(runnable) mThread?.start() mResultTextView.text = "Thread running..." } findViewById(R.id.stop_button)?.setOnClickListener { v -> this.runnable.isCancelled = true } 上面用到的Runnable是只做一件事的,如果是连续不断的循环很多事的话也可以使用white语句来控制是否一直执行线程的工作。一旦设置为停止线程,则停止线程任务的循环跳出Runnable#run()方法,结束线程。 完整代码放在附录中。 所以,如果你在Activity里开辟了一个线程,在Activity被回收的时候结束线程就可以这么做: override fun onDestroy() { super.onDestroy() this.runnable.isCancelled = true } 这样就再也不用担心Activity挂了,线程还阴魂不散了。 AsyncTask 既然缘起AsyncTask那就肯定需要读者一起了解一下相关的概念。 比起来使用Handler+Thread+Runnable的多线程异步执行模式来说,使用AsyncTask是简单了非常的多的。 先简单了解一下AsyncTask。 public abstract class AsyncTask<Params, Progress, Result> AsyncTask是一个抽象泛型类。三个类型Params,Progress,Result分别对应的是输入参数的类型,精度更新使用的类型,最后是返回结果的类型。其中任何一个类型如果你不需要的话,可以使用java.lang.Void代替。 继承AsyncTask给出自己的实现,最少需要实现doInBackground方法。doInBackground方法是在后台线程中运行的。如果要在任务执行之后更新UI线程的话还至少需要给出onPostExecute方法的实现,在这个方法中才可以更新UI。 上述的两个方法已经构成了一个AsyncTask使用的基本单元。在后台线程处理一些任务,并在处理完成之后更新UI。但是如果一个任务比较长,只是在最后更新UI是不够的,还需要不断的提示用户已经完成的进度是多少。这就是需要另外实现onProgressUpdate方法。并在doInBackground方法中调用publishProgress方法发出每个任务的处理进度。 这个AsyncTask总体上就是这样的了: inner class DemoAsyncTask() : AsyncTask<String, Int, String>() { // var isRunning = true override fun doInBackground(vararg params: String?): String? { Log.i(TAG, "##AsyncTask doing something...") var i = 0 val TOTAL = 100000000 var progress = 0 while (i < TOTAL) { Log.d(TAG, "doning jobs $i is cancelled $isCancelled") i++ var currentProgress = i.toFloat() / TOTAL if (currentProgress > progress && Math.abs(currentProgress - progress) > 0.1) { progress = currentProgress publishProgress((progress * 100).toInt()) } } } Log.d(TAG, "doing jobs $i is cancelled $isCancelled") return "Task done" } override fun onPostExecute(result: String?) { this@CancalableActivity.mAsyncTextView?.text = result } override fun onProgressUpdate(vararg values: Int?) { mAsyncTextView?.text = "${mAsyncTextView?.text ?: "Async task..."} progress: ${values?.get(0) ?: 0}" } } 到这里各位读者应该对AsyncTask已经有一个总体的认识了。后台任务在doInBackground处理,处理过程的百分比使用publishProgress方法通知,并在onProgressUpdate方法中更新UI的百分比。最后任务处理全部完成之后在onPostExecute更新UI,显示全部完成。 怎么取消一个任务的执行呢?这个机本身还上面的线程的取消基本上一样。只是AsyncTask已经提供了足够的属性和方法完成取消的工作。直接调用AsyncTask#cancel方法就可以发出取消的信号,但是是否可以取消还要看这个方法的返回值是什么。如果是true那就是可以,否则任务不可取消(但是不可取消的原因很可能是任务已经执行完了)。 调用cancel方法发出取消信号,并且可以取消的时候。isCancelled()就会返回true。同时onPostExecute这个方法就不会再被调用了。而是onCancelled(object)方法被调用。同样是在doInBackground这个方法执行完之后调用。所以,如果想要在取消任务执行后尽快的调用到onCancelled(object)的话,就需要在onInBackground的时候不断的检查isCancelled()是否返回true。如果返回的是true就跳出方法的执行。 inner class DemoAsyncTask() : AsyncTask<String, Int, String>() { // var isRunning = true override fun doInBackground(vararg params: String?): String? { Log.i(TAG, "##AsyncTask doing something...") var i = 0 val TOTAL = 1000000 var progress = 0.0f while (i < TOTAL && !isCancelled) { Log.d(TAG, "doning jobs $i is cancelled $isCancelled") i++ var currentProgress = i.toFloat() / TOTAL if (currentProgress > progress && Math.abs(currentProgress - progress) > 0.1) { progress = currentProgress publishProgress((progress * 100).toInt()) } } Log.d(TAG, "doning jobs $i is cancelled $isCancelled") return "Task done" } override fun onPostExecute(result: String?) { this@CancalableActivity.mAsyncTextView?.text = result } override fun onProgressUpdate(vararg values: Int?) { mAsyncTextView?.text = "${mAsyncTextView?.text ?: "Async task..."} progress: ${values?.get(0) ?: 0}" } override fun onCancelled() { Log.i(TAG, "##Task cancelled") // isRunning = false this@CancalableActivity.mAsyncTextView?.text = "###Task cancelled" } // override fun onCancelled(result: String?) { // Log.i(TAG, "##Task cancelled") //// isRunning = false // this@CancalableActivity.mAsyncTextView?.text = result ?: "Task cancelled" // } } onCancelled()是API level 3的时候加入的。onCancelled(Result result)是API level 11的时候加入的。这个在兼容低版本的时候需要注意。 但是一点需要格外注意: AsyncTask一定要在UI线程初始化。不过在**JELLY_BEAN**以后这个问题也解决了。 总之,在UI线程初始化你的`AsyncTask`肯定是不会错的。 线程池 下面就来看看线程池的概念。顾名思义,线程池就是放线程的池子。把费时费力,或者影响响应用户操作的代码放在另外一个线程执行时常有的事。但是如果无顾忌的开辟线程,却会适得其反,严重的浪费系统资源。于是就有了线程池。线程池就是通过某些机制让线程不要创建那么多,能复用就复用,实在不行就让任务排队等一等。 这个机制在线程池的构造函数里体现的非常明显: public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) corePoolSize线程池里闲着也不回收的线程数量。除非allowCoreThreadTimeOut指定可以回收。 ** maximumPoolSize** 线程池允许的最大线程数。 ** keepAliveTime** 非核心线程(就是如果核心线程数量corePoolSize定义为1的话,第二个就是非核心线程)的超时时间。 unitkeepAliveTime的时间单位,毫秒,秒等。 ** workQueue** 存放execute(Runnable cmd)方法提交的Runnable任务。 ** threadFactory**线程池用来创建新线程用的一个工厂类。 ** handler**线程池达到最大线程数,并且任务队列也已经满的时候会拒绝execute(Runnable cmd)方法提交任务。这个时候调用这个handler。 知道以上基本内容以后,就可以探讨线程池管理线程的机制了。概括起来有三点: 如果线程池的线程数量少于corePoolSize的时候,线程池会使用threadFactory这个线程工厂创建新的线程执行Runnable任务。 如果线程池的线程数量大于corePoolSize的时候,线程池会把Runnable任务存放在队列workQueue中。 线程池的线程数量大于corePoolSize,队列workQueue已满,而且小于maximumPoolSize的时候,线程池会创建新的线程执行Runnable任务。否则,任务被拒。 现在回到AsyncTask。被人广为诟病的AsyncTask是他的任务都是顺序执行的。一个AsyncTask的实例只能处理一个任务。但是在AsyncTask后面处理任务的是一个静态的线程池。在看这个线程池SerialExecutor的execute方法实现: final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); public synchronized void execute(final Runnable r) { mTasks.offer(new Runnable() { public void run() { try { r.run(); } finally { scheduleNext(); } } }); if (mActive == null) { scheduleNext(); } } protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { // 执行一个task } } 这个线程池SerialExecutor在处理Runnable的传入参数的时候对这个任务进行了重新包装成了一个新的Runnable对象,并且将这个新的对象存入了一个叫做mTasks的队列。这个新的Runnable对象首先执行传入的任务,之后不管有无异常调用scheduleNext方法执行下一个。于是整体的就生成了一个传入的任务都顺序执行的逻辑。 这个线性执行的静态线程池SerialExecutor的实现非常简单。并不涉及到我们前文所说的那么多复杂的内容。在实现上,这个线程池只实现了线程池的最顶层接口Executor。这个接口只有一个方法就是execute(Runnable r)。另外需要强调一点:mTasks的类型ArrayDeque<T>是一个不受大小限制的队列。可以存放任意多的任务。在线程池的讨论中遇到队列就需要看看容量概念。 SerialExecutor只是进行了简单的队列排列。但是在scheduleNext方法的实现上又会用到一个复杂一些的线程池来执行任务的具体执行。这线程池叫做THREAD_POOL_EXECUTOR。我们来具体看看其实现: private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); private static final int CORE_POOL_SIZE = CPU_COUNT + 1; private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; private static final int KEEP_ALIVE = 1; public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); 这个线程池的实现非常具有现实价值。虽然稍后介绍的系统提供的几种线程池的实现就够用。但是难免遇到一些需要自定义线程池的情况。详细解析如下: CORE_POOL_SIZE线程池的核心线程数量为设备核心数加一。 ** MAXIMUM_POOL_SIZE** 线程池的最大线程数量为核心数的两倍加一。 ** KEEP_ALIVE** 线程池中非核心线程的超时时间为一秒。 ** sPoolWorkQueue ** 线程池存放任务的队列。最大个数为128个。参考上面说的线程池处理机制,会出现任务被拒的情况。排队的线程池SerialExecutor存放任务的队列是可以认为无限长的,但是THREAD_POOL_EXECUTOR的队列最多存放128个任务,加上线程池核心线程的数量,能处理的任务相对有限。出现任务被拒的情况的几率比较大。所以,往AsyncTask里直接添加Runnable对象的时候需要三思。 ** sThreadFactory** 线程池用来创建线程的工厂对象。ThreadFactory是一个只有一个方法Thread newThread(Runnable r);的接口。这里在实现的时候给新创建的线程添加了一个原子计数,并把这个计数作为线程名称传递给了线程的构造函数。 到这里,我们就已经很清楚AsyncTask是如何用一个极其简单的线程池SerialExecutor给任务排队的。又是如何使用一个复杂一些的线程池THREAD_POOL_EXECUTOR来处理具体的任务执行的。尤其是线程池THREAD_POOL_EXECUTOR,在我们实际应用一个自定义的线程池的时候在设定线程池核心线程数量,线程池最大线程数量的时候都依据什么?明显就是设备的CPU核心数。线程分别在不同个CPU核心中做并行的处理。核心数多可以同时处理的线程数就相对较多,相反则会比较少一些。如此设置核心线程数量就会平衡并行处理的任务数量和在处理的过程中耗费的系统资源。 为了让开发者省时省力,系统默认的提供了四种可以适应不同应用条件的线程池: public class Executors { public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); } public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); } public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); } } ** newFixedThreadPool** 顾名思义,线程数量固定的线程池,且其数量等于参数指定值。这一类型的线程池的核心线程数量和最大线程数量是一样的。存放任务的队列的容量可以被认为无限大。一旦线程池创建的线程数量等* nThreads*参数值的时候,新增的任务将会被存放在任务队列中等待核心线程可用的时候执行。 ** newSingleThreadExecutor**newFixedThreadPool的一个特殊情况,当mThreads值为1的时候。 ** newCachedThreadPool** 这一类型的线程池中创建的线程都有60秒的超时时间,由于超时时间比较长等于是线程空闲了以后被缓存了60秒。由于核心线程数量为0,所以创建的线程都是非核心线程。也因此超时时间才管用。任务队列SynchronousQueue非常特殊,简单理解就是一个任务都存放不了。而线程池的最大线程数量又设定为Integer.MAX_VALUE,可以认为是无限大。根据线程池处理任务的机制,可以认为有新任务过来就会创建一个线程去处理这个任务,但是如果存在空闲没有超时的线程会优先使用。 ** newScheduledThreadPool** 生成一个ScheduledThreadPoolExecutor实例。可以通过其提供的接口方法设定延迟一定的时间执行或者隔一定的时间周期执行。 来一个例子: import static java.util.concurrent.TimeUnit.*; class BeeperControl { private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); public void beepForAnHour() { final Runnable beeper = new Runnable() { public void run() { System.out.println("beep"); }; final ScheduledFuture beeperHandle = scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS); scheduler.schedule(new Runnable() { public void run() { beeperHandle.cancel(true); } }, 60 * 60, SECONDS); } }} 附录 这里是上面例子中使用的全部代码。 线程的停止: package demo.retrofit2rxjavademo.Activities import android.os.Bundle import android.os.Handler import android.os.Message import android.support.v7.app.AppCompatActivity import android.widget.TextView import demo.retrofit2rxjavademo.R class CancalableActivity : AppCompatActivity() { lateinit var mResultTextView: TextView var mHandler = object : Handler() { override fun handleMessage(msg: Message?) { when (msg?.what) { THREAD_CANCELLED -> { mResultTextView.text = "thread cancelled" } THREAD_FINISHED -> { mResultTextView.text = "thread finished" } else -> { mResultTextView.text = "what's going on" } } } } var mThread: Thread? = null var runnable = object : CancelableRunnable() { override fun run() { if (isCancelled) { var msg = mHandler.obtainMessage(THREAD_CANCELLED) mHandler.sendMessage(msg) return } Thread.sleep(2000) if (isCancelled) { var msg = mHandler.obtainMessage(THREAD_CANCELLED) mHandler.sendMessage(msg) return } var msg = mHandler.obtainMessage(THREAD_FINISHED) mHandler.sendMessage(msg) } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_cancalable) mResultTextView = findViewById(R.id.run_result_text_view) as TextView findViewById(R.id.start_button)?.setOnClickListener { v -> runnable.isCancelled = false mThread = Thread(runnable) mThread?.start() mResultTextView.text = "Thread running..." } findViewById(R.id.stop_button)?.setOnClickListener { v -> this.runnable.isCancelled = true } } abstract class CancelableRunnable() : Runnable { var isCancelled: Boolean = false } companion object { val THREAD_FINISHED = 0 val THREAD_CANCELLED = 1 } } 欢迎加群互相学习,共同进步。QQ群:iOS: 58099570 | Android: 572064792 | Nodejs:329118122 做人要厚道,转载请注明出处! 本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sunshine-anycall/p/5506154.html ,如需转载请自行联系原作者

优秀的个人博客,低调大师

中国装备制造业寻找新路径:不数字化未来

经济学家、中国社科院学部委员吕政前不久总结,从1949到远期2049年上下一百年的时间维度来看,中国制造业的发展可以用简单的12个字来概括“从无到有,从少到多,从大到强”,中国毫无疑问的成了世界工厂。 但同时,吕政教授也认为现在的中国制造也正面临很大的麻烦。造成问题的原因有很多,但核心的有这样几个。首先是固定资产投资增速和5年前相比下降了两位数。其次是中国大规模的基础设施建设已经逐渐减少。一直占中国经济增长大头的房地产开发也已经从之前20%增长降到5%左右。市场需求变了,制造业的景气也结束了。更何况,人口红利消失带来的成本上升,也让人力成本占比极高的制造业举步维艰。 在众多制造业细分行业,装备制造业又是受伤害最大的一个行业。因为无论是基础建设,还是房地产,用到最多的制造业产品,除了水泥沙子等大宗原材料,剩下最重要的就是装备制造业这些施工设备。其实即使宏观环境没有变化,制造业可能也面临转型升级的问题。欧美等发达国家的制造业已经更早遇到了需求不足和成本过高的问题。相比较而言,中国市场的宏观环境已经不能算差。涉及多区域运营的跨国公司在这方面有更切身的体会,英特尔中国区总经理夏乐蓓在2015年9月18日第九届政企信息化策略研讨会上就表示,中国在任何行业的发展速度都很快,尤其是制造业,在全球来看都属于增长速度最快的国家行列。 装备制造业数字化云是第一步 正因为有了这样的发展空间。在有挑战的地方,就存在机会。高额固定资产投入带来的快钱不好赚了,中国制造业到了苦练内功的时候,尤其装备制造业是其中最大的门类,也是中国制造2025最重要的门类,所以装备制造业的问题可以上升为整个制造业的问题。 这一切对于工作在装备制造领域十余年的“青岛冷箱”数字化IT项目经理耿峰来说有着最直观的认识,在他看来中国传统装备制造业本身就面临产品创新不足和内部有待优化两大问题。而这些问题可能之前因高增长被掩盖了。要解决这些问题,他的观点是:“产品创新需要利用先进制造技术(IT技术、自动化、机器人等)提升工艺(提高产品吸引力);内部优化则要使用精益制造的模式,从各个环节杜绝浪费。” 而要实现这两种转变,装备制造业马上要面临的问题就是提高对新兴技术的运用。换言之,就是利用IT,将传统工厂升级为数字化工厂。数字化工厂的建设已经成为装备制造业现阶段最重要的任务,但搭建数字化工厂并不是一蹴而就的,首先就要让IT环境适应从研发,到制造,再到后期运维,甚至产品(智能化产品)带来的弹性业务,高密度计算和全程数据可视化。 装备制造业在信息化的建设上走的都相对较早,有比较完整的基础。基础网络、PDM、HR、CRM、ERP等平台基本都建设完成。而当下马上要做的就是云计算上的部署。在英特尔全球数据中心企业应用总监Patrick Buddenbaum看来,企业的业务在发生变化时,云计算非常值得去应用,因为这样企业就有了非常灵敏的业务支持环境。 正因为如此,基于英特尔X86服务器实现虚拟化在装备制造业当中正变得非常主流,同时再部署云计算时也更加得心应手。正是因为有了标准化的工业标准架构,可以很好的降低TCO,同时在业务基于云后,可以明显缩短企业内部的业务部署时间,在工厂每一个环节都可能提出IT需求的时候,都能提高响应速度,提高制造业内部IT部门的服务水平。 由于之前所讲到的,装备制造业的IT建设较早,所以企业内部往往已经有了成熟的IT架构。所以转型云端,到底该怎么做,装备制造企业也说法不一。英特尔对于云计算的策略是“Cloud for All”,即云可以适用于所有类型的应用以及企业,这里就包括混合云的情况。这样的技术即满足了企业长期发展,又保护了企业的现有投资。 耿峰同时认为,云计算的好处还不限于此,“云计算可以把企业的能力和人才都解放出来,让他们去了解业务、钻研业务,站在业务的角度上回归信息化。”因为私有云可以实现起码四大效益:第一,大幅减少IT基础设施的成本和运营成本;第二,使IT基础设施更加稳定、可靠;第三,让IT运营更加灵活高效;第四,节能减排。 当然有了云的支持,还需要有端的配合。尤其在装备制造业中,生产过程是否透明是重中之重,这关乎着企业命脉,也是同其他的制造业最大的不同。装备制造企业的产线工人往往通过操作机器的看板或在监察室了解生产过程,因为设备不具备移动性,这也就要求一人一岗才能知道整个工厂的实时运行环境,第一时间发现问题。而有了移动终端接入云平台,可以很好的提高工厂效率。比如工人在报工上,可以更好的记录、统计和分析员工在项目及非项目上的各项工作任务内容和所花费的时间,考核员工绩效,核算项目人工成本。另外在物料呼叫或物料不良上通过终端可以及时反馈并处理。从管理者到调度班长都可以通过终端实时掌控整个生产过程。 现在基于标准架构的平板电脑,正成为诸多制造业的车间标配。因为大多装备制造企业基于X86的体系架构,可以实现平滑的迁移。加上英特尔平台的移动终端由于体系开放,终端类型众多,就比较受到IT负责人的关注。因为用户可以从待机时间,耐用性,无线天线的灵敏度等多个方面,不同层面的要求衡量比较,从而最终采购到适合的产品。 因此综合来看,基于云计算的应用平台在装备制造企业中可以对生产前、生产中、生产后的各项工作进行预测和监控,打造生产制造透明化、高效化、智能化新模式,实现由传统制造业向智慧制造的转型,提升生产效率和管理水平。 物联网添砖加瓦 数字化模式的核心在于精益制造,其是在装备制造业中最重要的一个理念。将整个制造过程更加透明,用数据打破之前信息传递的不对称,信息的通常也可以规避更多问题,从而保证生产有序的进行。有了云端环境的支持,数字化工厂还需要具备什么要素? 其实数字化工场涉及的元素非常广泛,在各种元素融合在一起后,才能完成一个顶层设计。在很多企业主眼里数字化工厂只是几条自动化生产线,那就大错特错。这只是个一个基础,数字化工厂是让每一个环节都全部实现自动化,这也是装备制造业相比于电子制造业所欠缺的部分。 全自动无人焊接生产线 因此,曾有人说,想要让数字化工厂一步到位最简单直接的办法是开设新厂,但这对于中国装备制造业企业来说,成本投入太高,大家更多的是改造现有工厂,逐步实现数字化。老旧的生产线需要进行自动化的改造,并使用信息化的手段,例如管理系统整合底层生产线、条形码、RFID等,同时整合上游ERP、CRM、PLM等系统。 有专家总结,未来的装备制造企业的数字化工厂要包含三部分,一是智能化的生产过程,这里面将来会把云的触角伸展到上面;二是智能化的仓储物流,其实现在制造业制约发展最大的瓶颈就是信息的不对称,因为在装备制造业,大量的数据采集跟传递还是通过简易的Excel表形式,这些数据真正传递到有效部门有大量的延迟,这样会引发出大量的质量问题、产量问题,甚至是影响到客户满意度;三是智能加工中心的生产线。 以上三个部分,数据采集和分析都是关键因素。因此物联网技术的应用,可能是除了云端环境外,数字化工厂最离不开的一个手段。而且物联网技术不仅要求有硬件的植入,也需要软件的配合。以英特尔的IoT平台为例,它采取的架构就是以X86为基础,采用Wind River全新边缘设备管理软件,帮助设备进行配置、迁移文件、捕捉和分析数据等。 有了云端计算环境,有了物联网进行连接和数据收集。接下来就是装备制造业的问题就在于如何进行数据分析。英特尔是一个高科技公司,其所生产的的芯片更是一个高精度制造业产品,所以英特尔对数据的重要性有非常深刻的体会。 英特尔产品(成都)有限公司制造信息部总经理钱静波在12月份的中国制造千人会(MIC1000)就提到数据对于数字化工厂的重要性。他认为,第一部分就是能实现实时流程控制,在快速响应的数字化工厂中,设备一旦报警会立刻进行处理。第二,优化生产流程。第三,基于预测的设备维护优化。第四,普及自动化和机械控制提高生产速度。而这些都基于物联网和数据分析的能力。 当然,可能需要再次强调的是,远程云端(服务器,数据中心等软硬环境)的支持依然是最首要的基础。数字化工厂的建设和改造对于装备制造业的整体提升不言而喻,但是数字化工厂和传统工厂的区别太过巨大,践行之路必定需要解决很多具体问题,而且由于结合了互联网这样一个重要出口,很多技术问题最后会上升到商业模式问题。全球著名的装备制造业企业徐工集团的首席信息官、徐工信息技术股份有限公司总经理张启亮认为,从“互联网+工程机械”来看,就体现在研发的数字化、生产制造智能化、营销互联网化、售后服务智能化、产品功能智能化、后市场管理移动化等多个方面。 英特尔是工业互联网联盟的成员单位,英特尔中国区总经理夏乐蓓之前也表示,第三次工业革命时代有很多我们难以预料的新挑战,说得容易做起来难。不过对于这场数字化浪潮的结果,无论是作为提供IT手段的公司,还是本身就是高精尖制造业企业,夏乐培还是非常乐观的,从英特尔的角度看,“是有能力提供这样的技术,让中国更好地利用互联网时代带来的这些新机遇的”。 原文发布时间为:2016-7-14 本文作者:王聪彬 本文来自云栖社区合作伙伴至顶网,了解相关信息可以关注至顶网

优秀的个人博客,低调大师

Python 爬吴亦凡的 10 万转发数据,扒一扒流量的真假!

由于时间点也挺凑巧,刚好赶在蔡徐坤发律师函给哔哩哔哩之后,不禁让大家对他们进行一番对比。同为我们印象中的流量明星,吴亦凡跟蔡徐坤之间有什么不一样吗?大伙儿是怎么看待他们的?又是怎么看待《大碗宽面》这首歌的呢? 我们通过微博移动端随机抓取了吴亦凡发布新歌《大碗宽面》的微博转发数据10万条(时间节点2019年4月20日01时)。该微博于2019年4月19日10时发布,到4月20日01时已被转发超过36万。 吴亦凡该微博的转发是否存在假流量? 当然,关注我的朋友们估计最关心的问题是,吴亦凡的微博转发是否像蔡徐坤一样,有很多都是假流量? 我们先从粉丝性别比例入手。我们统计了102118条转发数据中,有77279条是女性转发的,占75.7%,其余24839条是男性转发的,占24.3%。这是一个比较合理的比例。 我们随机抽取了男性的转发,发现这里的男粉丝几乎都是有简介、微博粉丝数、关注数都大于50的真粉丝。 咦,不是说吴亦凡是流量明星吗?难道很多假流量都存在于女性的转发里?我们又随机抽取了女性转发的数据,发现,这里面的女性粉丝几乎也都是有简介、微博粉丝数、关注数都大于50的真粉丝。 我们就更奇怪了:吴亦凡的假流量哪儿去了? 我们按照跟蔡徐坤一样的标准,把转发数据中转发者的关注或者粉丝数少于等于5、没有简介、转发之后被点赞数评论数再转发数都为0、微博会员等级为0级的数据(注意,这里的条件都是“且”的关系,而不是“或”,也就是需要满足所有条件才会被判定是假粉丝),以及转发者的关注或者粉丝数大于等于5但昵称长“用户XXXXXXXX”这样的数据抽取了出来。看看吴亦凡的真假流量各是多少。 可见,吴亦凡的《大碗宽面》微博102118条转发中,只有6100条是疑似假粉丝转发的,占6%,有94%都是真粉丝转发的。这跟蔡徐坤的转发数据截然相反。 96018条真粉丝转发的数据中,除去重复转发刷榜的数量,里面还有81872个真粉丝。也就是说,真实转发的粉丝数量,占总转发量的80.2%。这比蔡徐坤3.84%的真实转发粉丝数量高出了一大截。也说明至少在这首歌上,吴亦凡的假流量占比是很少的。这首歌能火起来,靠的是大家对这首歌的接受度。 大家对于《大碗宽面》怎么看? 既然这样,那大家是以一种什么样的态度看待这首歌的呢?我们利用SnowNLP这个中文文本挖掘库对转发中所带的每一条评论进行情感倾向分析并打分(分值为0-1,越接近0情感越负面,越接近1情感越正面,0.5为中立)。 所有转发所带的评论,对《大碗宽面》的平均情感倾向评分是0.686。也就是大家整体对于这首歌的评论都是偏正面的,这跟这首歌的豆瓣评分6.5分(10分制)也相差不远。 随机抽取出情感倾向高的评论,大家都认为吴亦凡可以自嘲自黑很酷、很接底气、很可爱,认为吴亦凡可以通过这种方式来破网友对自己的吐槽梗,心胸很开阔。跟律师函警告相比之下,不知道高出了多少。 有多少人拿吴亦凡与蔡徐坤作对比? 由于这首歌发布的时间比较凑巧,刚好在蔡徐坤发律师函给哔哩哔哩并引起网友一阵吐槽之后,所以大家难免会把吴亦凡和蔡徐坤放在一起比较。那么,拿他们两个一起比较的人多吗? 我们把评论中带有跟蔡徐坤有关字眼(比如包含“kun”、“坤”、“律师函”等)的评论都抽了出来,发现足足有6229条,也就是大概15条评论中,就有一条把他们两个放在一起比较的。 抽取其中点赞数最高的10条,看看大家都怎么进行比较的。 大伙儿都对吴亦凡的公关团队表示佩服,可以把槽点转变为亮点,有很多人佩服吴亦凡的气度和格局,还有很多人认为这和律师函相比,高下立判。 有多少人开始路转粉了? 既然这首歌风评那么好,是不是很多人开始路转粉了呢?我们把带有“转粉”、“圈粉”等字眼的评论抽取了出来,发现这里面有足足3646条评论是关于转粉的。 而这3646条评论中,有2441条是女性的评论,还有1205条是男性的评论,占1/3!按照比例保守估计,目前37万的转发中,吴亦凡已成功圈粉13000人!并且使很多原来不喜欢他的黑粉,开始转变为路人。 评论的词云图 按照惯例,我们把转发中所带的评论制作成了词云图。 如果你在学习Python的过程当中有遇见任何问题,多多交流问题,互帮互助,群里有不错的学习教程和开发工具。学习python有任何问题(学习方法,学习效率,如何就业),可以随时来咨询我 可以看到: 1. 正如微博配词所说“大碗宽面能让你开心,这确是我本意”,大家对于这首自嘲歌的最大反应是“哈哈哈”; 2. 大家觉得这首歌很好听、有趣、有意思,觉得吴亦凡很可爱; 3. 有人第一次对吴亦凡说了“对不起”,对吴亦凡开始有Respect,开始路转粉; 4. 还有人拿蔡徐坤出来比较,拿律师函出来调侃。 看来,在娱乐圈里生存,开阔的心胸和善于自嘲的态度是很必要的。眼看着吴亦凡被万千吐槽,今天还能收获掌声一片,从一开始的流量明星转变为一个具有真流量的谐星。 所以说,千万别虚荣心作祟,娱乐圈嘛,快乐才是真谛,何必针锋相对。有时候不缺硬刚的勇气,缺的是娱乐的智慧。人生如戏开个玩笑,听完歌就洗洗睡。

优秀的个人博客,低调大师

【资料下载】Python 第三讲——正则表达式爬糗事百科数据

直播时间:2月20日 20:00—21:00 直播讲师:罗攀——林学研究生《从零开始学Python网络爬虫》作者《从零开始学Python数据分析》作者。擅长网络爬虫、数据分析,在web开发,数据库,机器学习等领域有所涉猎 随着Internet的飞速发展,互联网每天都会产生大量的非结构化数据。如何从这些非结构化数据中提取有效的信息,供学习、工作使用,网络爬虫应运而生。由于Python语言简单易用、优秀易用的第三方库和多样的爬虫框架,让Python语言成为了网络爬虫的主力军。本次直播通过简单案例,让大家感受Python的强大,以及爬虫的乐趣 欢迎扫码观看直播 或点击链接:http://tb.cn/UQkRRHw PPT下载:https://yq.aliyun.com/download/3320视频链接:https://yq.aliyun.com

优秀的个人博客,低调大师

Python爬虫学习,记一次抓包获取js,从js函数中数据的过程

昨天有小伙伴找我,新浪新闻的国内新闻页,其他部分都是静态网页可以抓到,但是在左下方的最新新闻部分,不是静态网页,也没有json数据,让我帮忙抓一下。大概看了下,是js加载的,而且数据在js函数中,很有意思,就分享出来给大家一起看看! 抓取目标 今天我们的目标是上图红框部分,首先我们确定这部分内容不在网页源代码中,属于js加载的部分,点击翻页后也没有json数据传输! 但是发现有个js的请求,点击请求,是一行js函数代码,我们将其复制到json的视图查看器中,然后格式化一下,看看结果 发现里面有可能存在我们需要的内容,比如url、title、intro这3个参数,猜测就是对应的新闻URL、标题、简介 只是其内容,需要在进行处理一下,我们写到代码中看看 开始写代码 先导入库,因为最终需要从字符串中截取部分,所以用requests库获取请求,正则re匹配内容即可。然后我们先匹配出上述3项 可以看到,url中存在 \ \,标题和简介是以\ \ u4e09的形式存在,这些就是我们需要处理的下一步了! 先用replace函数剔除url中\ \,即可得到url,后面的\ \ u4e09则是unicode编码,可以直接解码得到内容,直接写代码了 解码用了eval函数,内容为u“ + unicode编码内容 + “的形式即可解码! 这样,就取出了本页的所有新闻和URL的相关内容,在外层加上循环,即可抓取所有的新闻页,任务完成! 后记 新浪新闻的页面js函数比较简单,可以直接抓到数据,如果是比较复杂的函数的话,就需要深入理解前端知识了,这也是为什么学爬虫,需要学习前端知识的原因! ps:上文所用的json查看器是第三方的网站,直接百度即可找到很多,当然也可以直接将上述抓包的内容修改,然后用json读取数据也是可以的! 基本代码没有多少,如果有看不清楚的小伙伴,可以私信我获取代码或者一起研究爬虫哦!

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册