精华内容
下载资源
问答
  • ViewPager取消预加载

    热门讨论 2013-11-02 20:58:26
    ViewPager取消预加载专用jar包,修改android support v4后的
  • ViewPager+Fragment取消预加载(延迟加载)

    千次下载 热门讨论 2015-01-12 16:49:23
    ViewPager+Fragment取消预加载(延迟加载),详情请看:http://blog.csdn.net/myatlantis/article/details/42643733
  • C# task 取消

    千次阅读 2018-12-24 10:27:46
    在4.0中给我们提供一个“取消标记”叫做CancellationTokenSource.Token,在创建task的时候传入此参数,就可以将主线程和任务相关联,然后在任务中设置“取消信号“叫做ThrowIfCancellationRequested来等待主线...

    1、需求 
     我们知道task是并行计算的,比如说主线程在某个时刻由于某种原因要取消某个task的执行,我们能做到吗? 当然我们可以做到。 
    在4.0中给我们提供一个“取消标记”叫做CancellationTokenSource.Token,在创建task的时候传入此参数,就可以将主线程和任务相关联,然后在任务中设置“取消信号“叫做ThrowIfCancellationRequested来等待主线程使用Cancel来通知,一旦cancel被调用。task将会抛出OperationCanceledException来中断此任务的执行,最后将当前task的Status的IsCanceled属性设为true。 
    注意:一定要处理这个异常,可以通过调用Task.Result成员来获取这个异常。如果一直不查询Task的Exception属性。你的代码就永远注意不到这个异常的发生,如果不能捕捉到这个异常,垃圾回收时,抛出AggregateException,进程就会立即终止,这就是“牵一发动全身”,莫名其妙程序就自己关掉了,谁也不知道这是什么情况。所以,必须调用前面提到的某个成员,确保代码注意到异常,并从异常中恢复。因此可以将条用Task的某个成员来检查Task是否跑出了异常,通常调用Task的Result。下面看代码:

            static void Main(string[] args)
            {
                var cts = new CancellationTokenSource();
                var ct = cts.Token;

                Task task1 = new Task(() => { Run1(ct); }, ct);

                Task task2 = new Task(Run2);

                try
                {
                    task1.Start();
                    task2.Start();
    //在这段时间内,ct.ThrowIfCancellationRequested();是不会被触发的
                    Thread.Sleep(1000);
                    cts.Cancel();
                    //这时候会触发ct.ThrowIfCancellationRequested();

                    Task.WaitAll(task1, task2);
                }
                catch (AggregateException ex)
                {
                    foreach (var e in ex.InnerExceptions)
                    {
                        Console.WriteLine("\nhi,我是OperationCanceledException:{0}\n", e.Message);
                    }

                    //task1是否取消
                    //Console.WriteLine("task1是不是被取消了? {0}", task1.IsCanceled);
                    //Console.WriteLine("task2是不是被取消了? {0}", task2.IsCanceled);
                }
                Console.WriteLine("task1是不是被取消了? {0}", task1.IsCanceled);
                Console.WriteLine("task2是不是被取消了? {0}", task2.IsCanceled);
                Console.Read();
            }

            static void Run1(CancellationToken ct)
            {
            //下面这句话是没有用的,因为这个时候没有收到Cancel的消息
                ct.ThrowIfCancellationRequested();

                Console.WriteLine("我是任务1");

                Thread.Sleep(2000);//是为了在Cancel的时候Run1没有执行完
    //当上面等到1000ms多的时候实际上已经接收到Cancel的消息了,但是这个时候不会取消task的,只有调用下面这句话的时候才会取消task
                ct.ThrowIfCancellationRequested();

                Console.WriteLine("我是任务1的第二部分信息");
            }

            static void Run2()
            {
                Console.WriteLine("我是任务2");
            }123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354

    注意: 
    1、只有ct.ThrowIfCancellationRequested();才能真正的取消Task,此外,ct.ThrowIfCancellationRequested();的调用必须是接收到Cancel命令过来才会触发的。 
    2、个人认为:这样子的目的是为了接收到取消的时候,不会立马停止Task,而是只有在合适的时间停止。 
    2、Task的写法:

    1.https://www.cnblogs.com/yunfeifei/p/4106318.html
    2.https://msdn.microsoft.com/zh-cn/library/system.threading.tasks.task.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1

    3.http://www.cnblogs.com/yunfeifei/p/4111112.html

    4.https://www.cnblogs.com/x-xk/tag/C%23线程/

    var cts = new CancellationTokenSource();
    var ct = cts.Token;
    Task task1 = new Task(() => { Run1(ct); }, ct);
     

    ///

    1.Task类介绍:

    Task 类的表示单个操作不返回一个值,通常以异步方式执行。 Task 对象是一个的中心思想 基于任务的异步模式 首次引入.NET Framework 4 中。 因为由执行工作 Task 对象通常以异步方式执行在线程池线程上而不是以同步方式在主应用程序线程,您可以使用 Status 属性,以及 IsCanceled, ,IsCompleted, ,和 IsFaulted 属性,以确定任务的状态。 大多数情况下,lambda 表达式用于指定的任务是执行的工作。

    对于返回值的操作,您使用 Task 类。

    任务Task和线程Thread的区别:

    1、任务是架构在线程之上的,也就是说任务最终还是要抛给线程去执行。

    2、任务跟线程不是一对一的关系,比如开10个任务并不是说会开10个线程,这一点任务有点类似线程池,但是任务相比线程池有很小的开销和精确的控制。

    Task和Thread一样,位于System.Threading命名空间下!

    一、创建Task

    Task 类还提供了构造函数对任务进行初始化,但的未计划的执行。 出于性能原因, Task.Run 或 TaskFactory.StartNew(工厂创建) 方法是用于创建和计划计算的任务的首选的机制,但对于创建和计划必须分开的方案,您可以使用的构造函数(new一个出来),然后调用 Task.Start 方法来计划任务,以在稍后某个时间执行。

     //第一种创建方式,直接实例化:必须手动去Start
       var task1 = new Task(() =>
        {
           //TODO you code
        });
       task1.Start();
    
    //第二种创建方式,工厂创建,直接执行
       var task2 = Task.Factory.StartNew(() =>
        {
         //TODO you code
        });
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    二、Task的简略生命周期:

    方法名说明
    Created表示默认初始化任务,但是“工厂创建的”实例直接跳过。
    WaitingToRun这种状态表示等待任务调度器分配线程给任务执行。
    RanToCompletion任务执行完毕。
    //查看Task中的状态
       var task1 = new Task(() =>
             {
                Console.WriteLine("Begin");
                System.Threading.Thread.Sleep(2000);
                Console.WriteLine("Finish");
             });
             Console.WriteLine("Before start:" + task1.Status);
             task1.Start();
             Console.WriteLine("After start:" + task1.Status);
             task1.Wait();
             Console.WriteLine("After Finish:" + task1.Status);
    
             Console.Read();
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    三、Task的任务控制:Task最吸引人的地方就是他的任务控制了,你可以很好的控制task的执行顺序,让多个task有序的工作

    方法名说明
    Task.Waittask1.Wait();就是等待任务执行(task1)完成,task1的状态变为Completed。
    Task.WaitAll待所有的任务都执行完成:
    Task.WaitAny发同Task.WaitAll,就是等待任何一个任务完成就继续向下执行
    Task.ContinueWith第一个Task完成后自动启动下一个Task,实现Task的延续
    CancellationTokenSource通过cancellation的tokens来取消一个Task。

    下面详细介绍一下上面的几个方法:

    1、Task.Wait

    task1.Wait();就是等待任务执行(task1)完成,task1的状态变为Completed。

    2、Task.WaitAll

    看字面意思就知道,就是等待所有的任务都执行完成:

     {
    Task.WaitAll(task,task2,task3...N)
    Console.WriteLine("All task finished!");
    }
    • 1
    • 2
    • 3
    • 4

    即当task,task2,task3…N全部任务都执行完成之后才会往下执行代码(打印出:“All task finished!”)

    3、Task.WaitAny

    这个用发同Task.WaitAll,就是等待任何一个任务完成就继续向下执行,将上面的代码WaitAll替换为WaitAny

     {
    Task.WaitAny(task,task2,task3...N)
    Console.WriteLine("Any task finished!");
    }
    • 1
    • 2
    • 3
    • 4

    即当task,task2,task3…N任意一个任务都执行完成之后就会往下执行代码(打印出:” Any task finished!”)

    4、Task.ContinueWith

    就是在第一个Task完成后自动启动下一个Task,实现Task的延续,下面我们来看下他的用法,编写如下代码:

      static void Main(string[] args)
            {
                var task1 = new Task(() =>
                {
                    Console.WriteLine("Task 1 Begin");
                    System.Threading.Thread.Sleep(2000);
                    Console.WriteLine("Task 1 Finish");
                });
                var task2 = new Task(() =>
                {
                    Console.WriteLine("Task 2 Begin");
                    System.Threading.Thread.Sleep(3000);
                    Console.WriteLine("Task 2 Finish");
                });
                task1.Start();
                task2.Start();
                var result = task1.ContinueWith<string>(task =>
                {
                    Console.WriteLine("task1 finished!");
                    return "This is task result!";
                });
                Console.WriteLine(result.Result.ToString());
                Console.Read();
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    可以看到,task1完成之后,开始执行后面的内容,并且这里我们取得task的返回值。

    5、Task的取消

    前面说了那么多Task的用法,下面来说下Task的取消,比如我们启动了一个task,出现异常或者用户点击取消等等,我们可以取消这个任务。如何取消一个Task呢,我们通过cancellation的tokens来取消一个Task。在很多Task的Body里面包含循环,我们可以在轮询的时候判断IsCancellationRequested属性是否为True,如果是True的话就return或者抛出异常,抛出异常后面再说,因为还没有说异常处理的东西。

    下面在代码中看下如何实现任务的取消,代码如下:

        var tokenSource = new CancellationTokenSource();
                var token = tokenSource.Token;
                var task = Task.Factory.StartNew(() =>
                {
                    for (var i = 0; i < 1000; i++)
                    {
                        System.Threading.Thread.Sleep(1000);
                        if (token.IsCancellationRequested)
                        {
                            Console.WriteLine("Abort mission success!");
                            return;
                        }
                    }
                }, token);
                token.Register(() =>
                {
                    Console.WriteLine("Canceled");
                });
                Console.WriteLine("Press enter to cancel task...");
                Console.ReadKey();
                tokenSource.Cancel();
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    这里开启了一个Task,并给token注册了一个方法,输出一条信息,然后执行ReadKey开始等待用户输入,用户点击回车后,执行tokenSource.Cancel方法,取消任务。

    展开全文
  • 取消对NUll指针的引用

    2020-02-19 19:58:03
    如题,而且运行过后它一直在输入也不输出 ``` #include #include struct student { char name[20]; int score; struct student* ...取消对 NULL 指针“pend”的引用。...取消对 NULL 指针“pnew”的引用。
  • 有的时候,我们在启动了一个协程之后,并不需要该协程执行完毕,这个时候我们可以取消该协程的执行。比如在Android开发中,我们打开了一个页面,我们在进入页面的时候启动了一个协程来发起了网络请求,但是用户立马...

    ​ 通过前面的三篇文章,我们已经讨论了协程的创建。有的时候,我们在启动了一个协程之后,并不需要该协程执行完毕,这个时候我们可以取消该协程的执行。比如在Android开发中,我们打开了一个页面,我们在进入页面的时候启动了一个协程来发起了网络请求,但是用户立马就关闭了页面,这个时候我们就可以取消这个协程的执行,因为我们已经不需要它的执行结果了。

    1. 我们先来回顾一下CoroutineScope.launch{}的方法签名:

      public fun CoroutineScope.launch(
          context: CoroutineContext = EmptyCoroutineContext,
          start: CoroutineStart = CoroutineStart.DEFAULT,
          block: suspend CoroutineScope.() -> Unit): Job
      

      可以看到,它有一个Job类型的返回值,它有对应的cancel()方法来取消执行的协程:

      fun main() = runBlocking {
      
          val job = launch {
              repeat(200) {
                  println("hello : $it")
                  delay(500)
              }
          }
      
          delay(1100)
          println("world")
      
          job.cancel()
          job.join()
      
          println("welcome")
      }
      

      运行结果为:

      hello : 0
      hello : 1
      hello : 2
      world
      welcome

      在delay 1100毫秒之后,由于在runBlocking协程(姑且称之)中调用了job.cancel()之后,launch协程(姑且称之)中原本会repeat 200次的执行,如今只计数到了2,说明的的确确被取消了。cancel()一般会和join()方法一起使用,因为cancel可能不会立马取消对应的协程(下面我们会提到,协程能够被取消,是需要一定条件的),所以会需要join()来协调两个协程。故而有个更加简便的方法:Job.cancelAndJoin(),可以用来替换上面的两行代码。

      public suspend fun Job.cancelAndJoin() {
          cancel()
          return join()
      }
      
    2. 协程能够被取消的前提条件

      只有协程代码是可取消的,cancel()才能起作用。

      Coroutine cancellation is cooperative. A coroutine code has to cooperate to be cancellable.

      这是官方的描述。我们来直接看一段代码:

      fun main() = runBlocking {
          
          val job = launch(context = Dispatchers.Default) {
      
              println("Current Thread : ${Thread.currentThread()}")
              var nextActionTime = System.currentTimeMillis()
              var i = 0
      
              while (i < 20) {
                  if (System.currentTimeMillis() >= nextActionTime) {
                      println("Job: ${i++}")
                      nextActionTime += 500
                  }
              }
          }
      
          delay(1300)
          println("hello")
      
          job.cancelAndJoin()
      
          println("welcome")
      }
      

      这段代码我们要注意两点:

      • 调用launch方法时,我们给其形参context多传递了一个Dispatcheres.Default参数。在这里我只告诉大家,这样使得launch启动的协程代码运行在一个新的子线程中,而不是和runBlocking协程一样(它是运行在主线程中)。(下一篇我们再来详细阐述这个地方)

      • 理解一下launch协程中的循环计算代码:

        第一次循环:i=0,同时 if条件肯定满足,输出”Job:0“,nextActionTime += 500

        第二次循环:由于nextActionTime在第一次循环中加了500,而且if中两行代码的执行时间肯定远远 不足500毫秒

        第…次循环:…

        直到等足了500毫秒,才第二次进入if条件,使用i++,nextActionTime += 500

        最终当i=20时,循环条件不满足,退出循环,至此launch协程代码执行完毕。

        在空等500毫秒中,实际上可以看做是死循环了500毫秒,并且一直占用着cpu。

      我们来看运行结果:

      在这里插入图片描述

      按照我们本来的认知,在delay 1300毫秒之后,由于我们调用了cancelAndJoin方法,应该会取消launch子协程的运行才对(换句话说i最大值为2,而不会加到20才退出)。也就是说,取消没有成功。现在,我们再回过头来,理解”只有协程代码是可取消的,cancel()才能起作用“。那也就是说,这个示例中的launch协程的代码是不可取消的。那么什么样的代码才可以视为可取消的呢

      • kotlinx.coroutines包下的所有挂起函数都是可取消的。这些挂起函数会检查协程的取消状态,当取消时就会抛出CancellationException异常
      • 如果协程正在处于某个计算过程当中,并且没有检查取消状态,那么它就是无法被取消的

      很显然,我们上面示例中的代码就是计算过程中,所以它是无法被取消的。那么有没有什么方式使得这样的计算代码也变为可取消的呢?

      • 可以周期性地调用一个挂起函数,因为该挂起函数会取检查取消状态。
      • 显式地去检查取消状态

      下面我们就对刚刚的代码做一下改进:

      fun main() = runBlocking {
          val job = launch(Dispatchers.Default) {
      
              println("Current Thread : ${Thread.currentThread()}")
              var nextActionTime = System.currentTimeMillis()
              var i = 0
      
              while (isActive) {
                  if (System.currentTimeMillis() >= nextActionTime) {
                      println("Job: ${i++}")
                      nextActionTime += 500
                  }
              }
          }
      
          delay(1300)
          println("hello")
      
          job.cancelAndJoin()
      
          println("welcome")
      }
      

      输出结果:

      Current Thread : Thread[DefaultDispatcher-worker-1,5,main]
      Job: 0
      Job: 1
      Job: 2
      hello
      welcome

      这样我们就能成功的取消了计算过程中的协程。

      最后,我们对协程取消条件做一下总结:从某种角度上讲,是否能够取消是主动的;外部调用了cancel方法后,相当于是发起了一条取消信号;被取消协程内部如果自身检测到自身状态的变化,比如isActive的判断以及所有的kotlinx.coroutines包下挂起函数,都会检测协程自身的状态变化,如果检测到通知被取消,就会抛出一个CancellationException的异常。

    3. 下面看一波这样的示例代码:

      fun main() = runBlocking {
          val job = launch {
              try {
                  repeat(200) {
                      println("job: I am sleeping $it")
                      delay(500)
                  }
              }catch (e: CancellationException){
                  println("canceled")
              }
              finally {
                  println("finally块")
              }
          }
      
          delay(1300)
          println("hello")
      
          job.cancelAndJoin()
          println("welcome")
      
      }
      

      job: I am sleeping 0
      job: I am sleeping 1
      job: I am sleeping 2
      hello
      canceled
      finally块
      welcome

      这块可以说明两个问题:

      • 就是前面提到的CancellationException
      • 我们可以在finally代码块中对于一些资源的关闭和回收
    4. 现在有一个问题:对于大多数资源的关闭和回收(比如关闭文件、取消job等),都是瞬间的动作,都不会是阻塞的行为。可能在极少数情况下,关闭和回收的操作是阻塞的,是需要调用挂起函数的,但是在finally中,如果协程已经被取消,那么此时对于挂起函数的调用,都会抛出一个CancellationException的异常。那么这种情况下,我们又该如何去处理:

      fun main() = runBlocking {
          val job = launch {
              try {
                  repeat(200) {
                      println("job: I am sleeping $it")
                      delay(500)
                  }
              } finally {
                  withContext(NonCancellable){
                      println("finally块")
                      delay(1000)
                      println("after delay in finally block.")
                  }
              }
          }
      
          delay(1300)
          println("hello")
      
          job.cancelAndJoin()
          println("welcome")
      
      }
      
      /*
      Calls the specified suspending block with a given coroutine context, suspends until it completes, and returns the result.
      */
      public suspend fun <T> withContext(
          context: CoroutineContext,
          block: suspend CoroutineScope.() -> T
      ): T 
      
      public object NonCancellable : AbstractCoroutineContextElement(Job), Job {
        .....
      }
      
      • withContext: 在给定的协程上下文下调用指定的挂起代码块,会一直挂起,直到结果返回,后面在介绍协程在Android开发的应用时,会时常看到它的身影。

      • NonCancellable:它是一个object对象,并且它是不会被取消的,它的状态一直是active的。

        A non-cancelable job that is always [active][Job.isActive]. It is designed for [withContext] function
        * to prevent cancellation of code blocks that need to be executed without cancellation.
        
    5. CancellationException。既然当协程处于取消状态时,对于挂起函数的调用,会导致该异常的抛出,那么我们为什么没有在输出终端见到它的身影呢?因为kotlin的协程是这样规定的:

      That is because inside a cancelled coroutine CancellationException is considered to be a normal reason for coroutine completion.

      也就是说,CancellationException这个异常是被视为正常现象的取消。

    6. 父子协程的取消。

      前面我们已经讨论了协程的取消自身的种种,那么如果父协程取消,对子协程有什么影响呢?同样地,子协程的取消,会对父协程有什么影响呢?

      /* Jobs can be arranged into parent-child hierarchies where cancellation
      * of a parent leads to immediate cancellation of all its [children]. Failure or cancellation of a child
      * with an exception other than [CancellationException] immediately cancels its parent. This way, a parent
      * can [cancel] its own children (including all their children recursively) without cancelling itself.
      *
      */
      

      这一段是Job这个接口的文档注释,我截取了一部分出来。我们一起来看下这段文档说明:

      Job可以被组织在父子层次结构下,当父协程被取消后,会导致它的子协程立即被取消。一个子协程失败或取消的异常(除了CancellationException),它也会立即导致父协程的取消。

      下面我们就通过代码来证明这一点:

      a. 父协程取消对于子协程的影响:

      fun main() = runBlocking {
      
          val parentJob = launch {
              launch {
                  println("child Job: before delay")
                  delay(2000)
                  println("child Job: after delay")
              }
      
              println("parent Job: before delay")
              delay(1000)
              println("parent Job: after delay")
          }
      
          delay(500)
          println("hello")
      
      }
      

      这是没调用cancel的代码,输出结果如下:

      parent Job: before delay
      child Job: before delay
      hello
      parent Job: after delay
      child Job: after delay

      做一下变动:

      fun main() = runBlocking {
      
          val parentJob = launch {
              launch {
                  println("child Job: before delay")
                  delay(2000)
                  println("child Job: after delay")
              }
      
              println("parent Job: before delay")
              delay(1000)
              println("parent Job: after delay")
          }
      
          delay(500)
          parentJob.cancelAndJoin()
          println("hello")
      
      }
      

      我们在delay(500)之后添加一行:parentJob.cancelAndJoin(),再看输出结果:

      parent Job: before delay
      child Job: before delay
      hello

      可以看到,我们一旦取消父协程对应的Job之后,子协程的执行也被取消了,那么也就验证父协程的取消对于子协程的影响。

      b. 子协程正常的CancellationException取消:

      fun main() = runBlocking {
      
          val parentJob = launch {
              val childJob = launch {
                  println("child Job: before delay")
                  delay(2000)
                  println("child Job: after delay")
      
              }
      
              println("parent Job: before delay")
              delay(1000)
              childJob.cancelAndJoin()
              println("parent Job: after delay")
          }
      
          delay(500)
          println("hello")
      
      }
      

      输出结果为:

      parent Job: before delay
      child Job: before delay
      hello
      parent Job: after delay

      可以看到,如果子协程是正常的取消(即CancellationException),那么对于父协程是没有影响的。

      c. 子协程的非CancellationException取消

      fun main() = runBlocking {
      
          val parentJob = launch {
              val childJob = launch {
                  println("child Job: before delay")
                  delay(800)
                  throw RuntimeException("cause to cancel child job")
              }
      
              println("parent Job: before delay")
              delay(1000)
              childJob.cancelAndJoin()
              println("parent Job: after delay")
          }
      
          delay(500)
          println("hello")
      
      }
      

      输出结果:

      parent Job: before delay
      child Job: before delay
      hello
      Exception in thread “main” java.lang.RuntimeException: cause to cancel child job

      这样非CancellationException导致的子协程地取消,也会导致父协程的取消。

    7. 提问:A协程有两个子协程B、C,如果B由于非CancellationException导致被取消,那么C会受到影响吗?

      这个也不难得出答案,B的非CancellationException导致的取消,自然会导致父协程A被取消,那么C作为A的子协程也会被取消。

    8. 说明:以上的讨论是返回Job的协程且不考虑SupervisorJob的存在,后面还会学习到返回Deferred的协程以及SupervisorJob(它和我们在Android开发中使用协程息息相关)。

    9. 协程的超时取消。

      如果用于执行某个任务的协程,我们设定,如果它超过某个时间后,还未完成,那么我们就需要取消该协程。我们可以使用withTimeout轻松实现这一功能:

      fun main() = runBlocking {
      
         val result =  withTimeout(1900) {
              repeat(3) {
                  println("hello: $it")
                  delay(400)
              }
            "hello world"
          }
      		println(result)
      }
      

      这种情况下没有超时,输出结果为:

      hello: 0
      hello: 1
      hello: 2

      “hello world”

      我们修改一下超时时间为1100,这时的输出结果为:

      hello: 0
      hello: 1
      hello: 2
      Exception in thread “main” kotlinx.coroutines.TimeoutCancellationException: Timed out waiting for 1100 ms

      这样就把超时转换成了普通的异常,我们可以对异常进行捕获:

      fun main() = runBlocking {
      
          try {
             val result =   withTimeout(1100) {
                  repeat(3) {
                      println("hello: $it")
                      delay(400)
                  }
                  "hello world"
              }
              println(result)
          } catch (e: TimeoutCancellationException) {
              println("超时取消")
          }
      }
      

      hello: 0
      hello: 1
      hello: 2
      超时取消

      与之类似地还有withTimeoutOrNull:

      fun main() = runBlocking {
      
          val result = withTimeoutOrNull(1900) {
              repeat(3) {
                  println("hello: $it")
                  delay(400)
              }
      
              "hello world"
          }
      
          println("the result is : $result")
      }
      

      输出结果为:

      hello: 0
      hello: 1
      hello: 2
      the result is : hello world

      再次修改超时时间:

      fun main() = runBlocking {
      
          val result = withTimeoutOrNull(1100) {
              repeat(3) {
                  println("hello: $it")
                  delay(400)
              }
      
              "hello world"
          }
      
          println("the result is : $result")
      }
      

      运行结果如下:

      hello: 0
      hello: 1
      hello: 2
      the result is : null

      可以看到,withTimeoutOrNull与withTimeout的区别在于,当发生超时取消后,withTimeoutOrNull的返回为null,而withTimeout会抛出一个TimeoutCancellationException。

      public suspend fun <T> withTimeoutOrNull(timeMillis: Long, block: suspend CoroutineScope.() -> T): T? {
          if (timeMillis <= 0L) return null
      
          var coroutine: TimeoutCoroutine<T?, T?>? = null
          try {
              return suspendCoroutineUninterceptedOrReturn { uCont ->
                  val timeoutCoroutine = TimeoutCoroutine(timeMillis, uCont)
                  coroutine = timeoutCoroutine
                  setupTimeout<T?, T?>(timeoutCoroutine, block)
              }
          } catch (e: TimeoutCancellationException) {
              // Return null if it's our exception, otherwise propagate it upstream (e.g. in case of nested withTimeouts)
              if (e.coroutine === coroutine) {
                  return null
              }
              throw e
          }
      }
      

      之所以有这样的区别,我们可以从withTimeoutOrNul的源码中得出答案:它对TimeoutCancellationException进行了捕获。

    展开全文
  • c# Task 之任务取消

    千次阅读 2020-04-13 16:52:59
    CLR via 一书中这样写到 ...如果 CacellationToken 在 Task 调度前取消, Task 会被取消,永远都不会执行。但是,如果Task 已调度,那么Task 为了允许它的操作在执行期间取消,Task 的代码就必须显示支持取...

    CLR via 一书中这样写到
    创建一个 Task 时,可以将一个 CancellationToken 传递给Task的构造器,从而将这个Cancellation 和该 Task 关联起来。如果 CacellationToken 在 Task 调度前取消, Task 会被取消,永远都不会执行。但是,如果Task 已调度,那么Task 为了允许它的操作在执行期间取消,Task 的代码就必须显示支持取消。
    来个试验:

    	static void Main(string[] args) {
                CancellationTokenSource tokenSource = new CancellationTokenSource();
                Task task1 = Task.Factory.StartNew(
                    () => taskRun("1"), tokenSource.Token
                    );
                Thread.Sleep(100);
                tokenSource.Cancel();
    			Thread.Sleep(2000);
                Console.WriteLine("task1是否取消:" + task1.IsCanceled);//task1.IsCanceled;
                                                                   //Console.WriteLine("task2是否取消:" + task2.IsCanceled);
                Console.ReadKey();
    
            }
    
            static void taskRun(object obj) {
                string id = obj as string;
    
                for (int i = 0; i < 1000; i++) {
                    Console.WriteLine("运行开始:" + i);
                    Thread.Sleep(1);
                }
            }
    

    开启一个任务,并在任务执行100ms 后调用CancellationTokenSource 的Cancel 函数。并在Cancel 执行后 输出 task1 是否取消
    这个任务从0打印到999。每次打印后线程睡眠1ms。
    在这里插入图片描述
    结果为任务未被取消!

    我把 Sleep(100) 删除后, 也就是开启任务后,马上调用Cancel 函数
    在这里插入图片描述
    从这里可以看出,在一个已经开始执行的任务时,单单使用Cancel 函数是不起作用的。任务根本不会被取消。

    取消一个已经运行的任务
    方法1:

    		static void Main(string[] args) {
                CancellationTokenSource tokenSource = new CancellationTokenSource();
                var tk = tokenSource.Token;
                Task task1 = Task.Factory.StartNew(
                    () => taskRun(tk), tk
                    );
                //Thread.Sleep(100);
                tokenSource.Cancel();
                Thread.Sleep(2000);
                Console.WriteLine("完成!" + task1.IsFaulted + "," + task1.IsCompleted + "," + task1.IsCanceled);
                Console.ReadKey();
    
            }
    
            static void taskRun(object obj) {
                CancellationToken ct = (CancellationToken)obj;
    
                for (int i = 0; i < 1000; i++) {
                    Console.WriteLine("运行开始:" + i);
                    Thread.Sleep(1);
    
                    ct.ThrowIfCancellationRequested();
                }
            }
    

    注意:此代码需要在外部运行,不要使用编辑器调试。(编辑器调试的情况 ct.ThrowIfCancellationRequested 会引发异常,会弹窗中断无法得到正确的结果)。

    运行结果
    在这里插入图片描述在任务中使用ct.ThrowIfCancellationRequested(); 如果任务在外部取消,将会抛出异常中断任务。在外部可以获得任务 已经完成 并且 已经取消的状态 这个要非常注意。
    IsCompleted 属性可能不是 真的完成,还可能被取消了。要配合 IsCanceled 一起使用。
    这里使用参数传递 CancellationToken,任务只支持一个参数,如果有多个参数要传递可以把参数包装成类,或者使用字典之类的容器来传递。

    方法2:
    自己定义取消标记,自己处理。

    		//是否取消
            volatile static bool IsCancel = false;
    
            static void Main(string[] args) {
                Task task1 = Task.Factory.StartNew(
                    ()=> taskRun()
                    );
                Thread.Sleep(100);
                IsCancel = true;
                Thread.Sleep(2000);
    
                Console.WriteLine("完成!" + task1.IsFaulted + "," + task1.IsCompleted + "," + task1.IsCanceled);
                //Console.WriteLine("task1是否取消:" + task1.IsCanceled);//task1.IsCanceled;
                                                                   //Console.WriteLine("task2是否取消:" + task2.IsCanceled);
                Console.ReadKey();
    
            }
    
            static void taskRun() {
                for (int i = 0; i < 1000; i++) {
                    Console.WriteLine("运行开始:" + i);
                    Thread.Sleep(1);
    
                    if(IsCancel)
                        return;
                }
            }
    

    运行结果
    在这里插入图片描述
    这里使用一个全局字段来控制任务是否取消。
    这里要注意的是用来表示任务取消标记的字段需使用volatile 关键字来标记字段为易变类型,否则可能无法正常取消任务!

    每次从属性CancellationTokenSource.Token获得的CancellationToken(值类型)是不是同一个值?

    CancellationTokenSource cts = new CancellationTokenSource();
                var tk1 = cts.Token;
                var tk2 = cts.Token;
    
                if(tk1 == tk2)
                    Console.WriteLine("同一个Token!");
                else
                    Console.WriteLine("不是同一个Token!");
    

    运行后得到 “同一个Token!”

    两个任务使用同一个CancellationTokenSource 取消任务会是怎么的结果?

    1. 如果在两个都还未运行的情况下,调用cancel() 函数,两个任务都会被取消,不会被运行。
    2. 先创建一个任务 然后调用cancel()函数,再创建一个任务。(未显示支持取消)。这时候不管第一个任务执行没执行。第二个任务肯定是不会执行。这里说明 cancel() 函数会把cancel() 调用之后创建的任务都取消掉(!
    3. 使用显示支持取消
            static void Main(string[] args) {
                CancellationTokenSource cts = new CancellationTokenSource();
                var tk1 = cts.Token;
                var tk2 = cts.Token;
                
                Task task1 = Task.Factory.StartNew(
                    ()=> taskRun(new List<Object>(){ "1", tk1 }),tk1
                    );
                Task task2 = Task.Factory.StartNew(
                    () => taskRun(new List<Object>() { "2" }), tk1
                    );
    
                Thread.Sleep(100);
                cts.Cancel();
    
                Thread.Sleep(2000);
    
                Console.WriteLine("完成1!" + task1.IsFaulted + "," + task1.IsCompleted + "," + task1.IsCanceled);
                Console.WriteLine("完成2!" + task2.IsFaulted + "," + task2.IsCompleted + "," + task2.IsCanceled);
                //Console.WriteLine("task1是否取消:" + task1.IsCanceled);//task1.IsCanceled;
                //Console.WriteLine("task2是否取消:" + task2.IsCanceled);
                Console.ReadKey();
    
            }
    
            static void taskRun(object obj) {
                var tp = obj as List<object>;
    
                CancellationToken tk;
                string id = tp[0] as string;
                if(tp.Count > 1)
                    tk = (CancellationToken)tp[1];
    
                for (int i = 0; i < 1000; i++) {
                    Console.WriteLine("运行开始:" + i + "," + id);
                    Thread.Sleep(1);
    
                    if (tp.Count > 1)
                        tk.ThrowIfCancellationRequested();
                }
            }
    

    运行结果
    在这里插入图片描述

    我开启了两个任务,两个任务使用同一个CancelltionTokenSource以及同一个CancelltionToken,在第一个任务中使用 tk.ThrowIfCancellationRequested(); 来显示取消任务。当两个任务在运行中,调用 cancel() 后,第一个任务被成功取消,第二个任务未被取消。这个结果非常有趣,两个任务使用的是同一个Token, 却只取消调用ThrowIfCancellationRequested() 函数的任务! (我猜测是ThrowIfCancellationRequested函数会返回当前运行的线程,然后把区分任务,把当前任务停止!)

    任务被取消,我读取任务的返回值会发生什么?
    如果任务已被取消,使用返回值会抛出 System.AggregateException 异常。

    任务取消是异步行为,使用Wait等待任务完成或取消会发生什么?
    如果任务已被取消,使用Wait同样抛出 System.AggregateException 异常

    展开全文
  • 取消当前请求-vue

    千次阅读 2021-09-16 19:58:51
    通过全局方法的引入,在页面直接调用该方法取消当前为完成的请求 无需引入,在使用vue的页面可直接使用 实现方式 新建JS文件,将代码(代码见下页)复制到JS文件中 在main.js中引入该JS文件,进行全局注入 (或者...

    在某些特殊的场景业务下,需要手动停止未完成的Ajax请求,或在快速切换页面时,停止上一页面未完成的请求,减少资源浪费

    实现目标:

    • 封装全局的变量及方法
    • 通过全局方法的引入,在页面直接调用该方法取消当前为完成的请求
    • 无需引入,在使用vue的页面可直接使用

    实现方式

      • 新建JS文件,单独封装方法
    • 在main.js中引入该JS文件,进行全局注入 (或者直接在main.js中注入方法)
    • 在单个请求中单独添加cancelToken标识
    • 全部请求(axios封装位置)发起时添加cancelToken标识
    • 调用全局方法停止当前正在进行的Ajax请求

    1、在main.js中注入方法

    /**
     *取消正在进行中请求
     * cancelList设置批量取消的接口,/**代表符合该规则的全部接口
     * * 全局方法$cancelRequest可取消当前cancelList中的正在请求requset
     * * 全局方法$cancelRequest("url")可控制取消单个请求
     * */
    const cancelDefaltList = ['/user/name','/org/number/**']
    Vue.prototype.$currentHttpRequestList = new Map();
    Vue.prototype.$cancelRequest = function(cancelkey) {
      if (cancelkey) {
        if (cancelkey.indexOf('/**') > -1) {
          Vue.prototype.$currentHttpRequestList.forEach((item, key) => {
            key.indexOf(cancelkey.split('/**')[0]) > -1 && item('Operation canceled by the user.');
          });
        } else {
          Vue.prototype.$currentHttpRequestList.get(cancelkey) && Vue.prototype.$currentHttpRequestList.get(cancelkey)('Operation canceled by the user.');
        }
      } else {
        cancelDefaltList.forEach(eachWite => {
          Vue.prototype.$currentHttpRequestList.forEach((item, key) => {
          key.indexOf(eachWite.split('/**')[0]) > -1 && item('Operation canceled by the user.')
          })
        })
     }
    };
    

    2、 在在请求拦截器中添加(也可以按照需求在某些请求中单独添加)cancelToken标识

    axios.interceptors.request.use(
      function(config) {
        const CancelToken = axios.CancelToken;
        var token = getToken();
        config.headers['Content-Type'] = 'application/json; charset=UTF-8';
        config.headers.Authorization = 'bearer ' + token; // 设置请求头
        //添加cancelToken标识
        config.cancelToken = new CancelToken(function executor(c) {
          Vue.prototype.$currentHttpRequestList.set(config.url, c);
        });
        return config;
      },
      function(err) {
        if (err && err.message === 'Operation canceld by the user.') {
          console.log(err, 'errorcancel');
          return;
        }
        return Promise.reject(err);
      }
    );
    

    3、按照需求(业务逻辑)调用全局方法停止当前正在进行的Ajax请求

    <template>
    </template>
    
    <script>
    export default {
      name: 'test',
      data() {
        return {};
      },
      created(){
          //实际使用位置需根据具体的业务场景需求而定,此处放在created中只是个示例
          this.$cancelRequest('/user/name/**');//取消以‘/user/name/’开头的正在进行中的请求
          this.$cancelRequest('/user/age');//取消正在进行中的请求‘/user/age/’
          this.$cancelRequest();  //取消cancelDefaltList设置的全部正在进行中的请求
      },
      methods: {}
    
    展开全文
  • 复制文件到一半时手动取消,一直显示正在取消状态 如何结束这个状态呢? 如下图: 也无法从进程中进行结束: 如下图: 这里提供了两种解决办法: 第一种:关机 重启 (这个方法简单 粗暴) 但是往往这样都是很费时间...
  • 自从微软推出了Win11操作系统之后,不少小伙伴都有下载体验,但很多小伙伴在使用一段时间后觉得每次开机都要输入密码都很麻烦,那么应该如何去取消开机密码呢?下面就和小编一起来看看应该怎么操作吧。 Win11开机密码...
  • 破解 Kotlin 协程(5) - 协程取消

    千次阅读 2019-04-30 15:31:48
    关键词:Kotlin 协程 协程取消 任务停止 协程的任务的取消需要靠协程内部调用的协作支持,这就类似于我们线程中断以及对中断状态的响应一样。 1. 线程的中断 我们先从大家熟悉的话题讲起。线程有一个被废弃的 ...
  • Ubuntu开机取消Grub引导界面

    万次阅读 2021-01-17 13:24:56
    Ubuntu开机取消Grub引导界面
  • javascript 实现取消promise

    千次阅读 2021-04-02 15:29:21
    Javascript 中,本身promise是不支持取消的,但是有时候,我们有些需求,希望能够取消。我们可以对异步请求进行封装,通过强制调用其reject,达到类似的取消操作。 function hello() { let _res, _rej; const ...
  • 取消网格线 splitLine: { show: false } 以下属性对x轴,y轴均有效 取消坐标轴刻度线 axisTick: { show: false } 取消显示坐标值 axisLabel: { show: false } 取消显示坐标轴 axisLine: { ...
  • 如何取消您的YouTube电视订阅

    千次阅读 2020-09-25 20:13:05
    从网上取消订阅 (Cancel Your Subscription From the Web) The easiest way to unsubscribe from YouTube TV is from the streaming service’s desktop website using your Windows 10, Mac, or Linux computer....
  • Latex取消缩进

    千次阅读 2020-12-17 13:49:42
    全局取消 \setlength{\parindent}{0pt} 单段取消 \noindent
  • 如何给Element 中的树型控件取消选中呢?我们不妨换一个思路来理解,即设置所勾选的节点数组为空,换句话来说就说让它什么也不选,这便达到取消选中的目的。 我们先来看看官方文档所提供的方法: 这样一来思路就比较...
  • 三小时未付款自动取消订单实现

    万次阅读 2018-09-12 21:41:20
    电商系统中,有这样的需求,用户下单三小时未支付就自动取消,具体如何实现的呢? 一、实现方案 通常实现方案有以下方式: 方式一 使用定时任务不断轮询取消,此种方式实现简单,但是存在一个问题,定时任务...
  • 进而引出一系列问题,如:1、radio单选框选中了如何取消取消了如何再选中;2、当checkbox选中状态发生变化时触发事件;3、操作checkbox复选框,radio单选框如何做出相对应的改变 二、案例解说 直接给你们抛详细...
  • 但是没有pthread那么强大,pthread有取消点函数,线程执行到取消点函数就会判断如何线程状态设置为取消,那么就会调用预先设定的线程清理函数清理资源,而取消点之后的代码块不会执行。而C++11并没有取消点的设计。...
  • git 取消托管文件

    千次阅读 2019-08-12 11:25:48
    如果想要取消托管某文件夹,通过如下命令能解决: git rm -r --cached .idea #--cached不会把本地的.idea删除 git commit -m '描述信息' git push -u origin master 假如该文件本地与版本库不一致,会删除失败 ...
  • RabbitMQ实现下单超时自动取消支付

    千次阅读 2020-08-07 20:41:35
    如果在这段时间内用户没有支付,则默认订单取消,该如何实现? 定期轮询(数据库等)用户下单成功,将订单信息放入数据库,同时将支付状态放入数据库,用户付款更改数据库状态。定期轮询数据库支付状态,如果超过30...
  • js radio取消选中

    千次阅读 2019-10-18 15:51:32
    $(document).ready(function () { $("input[type=radio]").click(function () { if ($(this).attr("tag") == 1) { $(this).attr("checked", false); $(this).a...
  • 套索工具如何取消

    千次阅读 2021-05-01 22:23:07
    1、套索工具画选区爱你还没松开单击的时候按ESC取消; 2、多边形套索工具按退格键是后退一步,按ESC直接取消; 3、磁性套索工具按退格键是删除上一个锚点,按ESC直接取消; 4、选区画好了用快捷键CTRL+D取消...
  • java 对于终止线程的考虑 Java没有提供任何机制来安全地(抢占式方法)终止线程, 虽然Thread.stop和suspend等方法提供了这样...一、取消 取消操作的原因 用户请求取消 有时间限制的操作 应用程序事件 错误...
  • Word 如何取消自动编号

    万次阅读 2021-06-06 11:32:42
    Word 如何取消自动编号 切换到【文件】选项卡,点击【选项】按钮,弹出【Word选项】对话框,切换到【校对】选项卡,点击【自动更正选项】按钮,弹出【自动更正】对话框,切换到【键入时自动套用格式】选项卡,取消...
  • RadioButton实现选择后可取消选择

    千次阅读 2019-07-31 13:35:41
    Radiobutton是一种单选按钮,是由于RadioGroup管理下的一组按钮,所以一旦其中的一个button选中,再点击,就不能取消,想要取消调用Radiobutton的setchecked(boolean isChecked)的方法。 在网上找了许多法,发现...
  • 据我所知,回滚其实用的很少,因为如果某次更新有问题,那么需要取消某次更新而不应该粗暴的回滚到那次更新之前(会操成误伤,抹去了别人的更新)。 所以推荐还是使用gir revert。 当然–soft 和–hard --mixed的...
  • 取消 Fetch 请求很简单

    千次阅读 2020-04-15 12:04:40
    JavaScript 的 promise一直是该语言的...原生 promise 的一个缺点是,到目前为止,还没有可以取消 fetch 的真正方法。 JavaScript 规范中添加了新的 AbortController,允许开发人员使用信号中止一个或多个 fetch 调用。
  • axios中取消请求及阻止重复请求的方法

    万次阅读 多人点赞 2019-06-26 11:10:55
    在Axios中取消请求最核心的方法是CanelToken。在官网文档中有写到两种方法使用CancelToken,这里简单粘贴出来,并增加了注释 方法1: const CancelToken = axios . CancelToken ; const source = ...
  • 有时候我们常常在发起一个请求时,希望取消前面的一个或多个请求,就要使用axios的一个方法CancelToken(), 配置方法如下。 在拦截器全局设置,用来取消所有请求: import axios from "axios"; window...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,360,899
精华内容 544,359
关键字:

取消