• C# Task异步任务


     Task用的是线程池,线程池的线程数量的有上限的,这个可以通过ThreadPool修改,我们经常会用到task.run ,new task ,和task.factory.startnew方法来创建任务

    Task.Factory.StartNew(action)不是直接创建线程,创建的是任务,它有一个任务队列,然后通过任务调度器把任务分配到线程池中的空闲线程中,任务是不能被直接执行的,只有分配给线程才能被执行,如果任务的数量比线程池中的线程多,线程池的线程数量还没有到达上限,就会创建新线程执行任务。如果线程池的线程已到达上限,没有分配到线程的任务需要等待有线程空闲的时候才执行。

    task 是新建一个异步任务,这个任务是分配到子线程中去的,跟我们之前的new thread,创建线程很相似,在子线程中,通过SynchronizationContext类进行上下文同步,实现子线程和主线程之间的通信。

    ContinueWith:创建一个在目标 Task 完成时异步执行的延续任务,也就是Task完成后要执行的任务

    示例代码如下:

    Task.Factory.StartNew(() =>
    {
    AddDr("select s_FilePathName from T_Files where isnull(s_FilePathName,'') <>''");
    }).ContinueWith(i =>
    {
    this.Invoke(new Action(delegate
    {
    lblProcess.Text = "数据库文件记录读取完成,共" + dt.Rows.Count + "个,开始执行复制...";
    //读取完成后,开始copy file 

    }));
    });

    task 和 thread ,以及thread pool区别:
    Task是将多个操作封装成一个概念上原子操作。但这个操作由哪个Thread甚至多个Thread来处理处理你并不清楚。总之就是可以被正常完成。
    Thread仅仅是一条线程,所有操作都是这个Thread一个完成的。

    thread是单核多线程,task是多核多线程

    task 比thread pool 线程池优越的地方在于,在thread pool时期,我们不能知道一个workitem是否完成,也不能在完成后知道workitem所得出的返回值,task封装后解决了这个问题,并且可以清楚地知道返回值。

    附上我自己写的一个文件复制的小demo代码:

    运行效果:

    代码如下:

    ----------------------------------------------------------------------------------------------------

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Data.SqlClient;
    using System.Drawing;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows.Forms;

    namespace CopyFiles
    {
    public partial class Form1 : Form
    {
    delegate void AsynUpdateUI(int step);

    public Form1()
    {
    InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
    SqlConnection con = new SqlConnection(string.Format("server={0};database={1};user={2};pwd={3};", txtServer.Text, txtDB.Text, txtSa.Text, txtPwd.Text));
    try
    {
    //2. 数据库操作类 关键字SqlCommand
    SqlCommand cm = con.CreateCommand();

    //编写TSQL语句
    cm.CommandText = "select count(*) from TCase_Base";

    //3. 数据库连接通道开启
    //上面只是连接到了数据库,并获取到了数据库的表的信息,需要开启才能实现操作
    con.Open();//开启

    //4. 数据读取类 关键字SqlDataReader
    SqlDataReader dq = cm.ExecuteReader();//读取一下获取到的数据库数据
    if (dq.HasRows) //if判断是否能够读取到数据库,读取到了走里面程序,读取不到说明有错误
    {
    while (dq.Read())//每次只读取一条数据,加个循环,将每条数据循环读取出来,每读到一条数据返回的是true类型,当没有数据的时候是false类型,自动结束循环
    {
    if (dq[0] != DBNull.Value)
    {

    }
    }
    }
    MessageBox.Show("测试连接成功!");
    }
    catch (Exception ex)
    {
    MessageBox.Show("测试连接失败!" + ex.Message);
    }
    finally
    {
    con.Close();//使用完之后关闭数据库连接
    }
    }

    private void button2_Click(object sender, EventArgs e)
    {
    FolderBrowserDialog dialog = new FolderBrowserDialog();
    dialog.Description = "请选择源文件目录";

    if (dialog.ShowDialog() == DialogResult.OK)
    {
    txtYFile.Text = dialog.SelectedPath;
    }
    }

    private void button3_Click(object sender, EventArgs e)
    {
    FolderBrowserDialog dialog = new FolderBrowserDialog();
    dialog.Description = "请选择目标文件目录";

    if (dialog.ShowDialog() == DialogResult.OK)
    {
    txtTFile.Text = dialog.SelectedPath;
    }
    }

    private DataTable dt;
    private void button4_Click(object sender, EventArgs e)
    {
    if (txtYFile.Text == "" && txtTFile.Text == "")
    {
    MessageBox.Show("源文件目录、目标文件目录不能为空!");
    return;
    }
    failList = new List<string>();
    this.button4.Enabled = false;
    dt = new DataTable();
    dt.Columns.Add("filepath", typeof(string));
    Task.Factory.StartNew(() =>
    {
    AddDr("select s_FilePathName from TFiles where isnull(s_FilePathName,'') <>''");
    AddDr("select s_EmailPath from TEmail where isnull(s_EmailPath,'') <>''");
    }).ContinueWith(i =>
    {
    this.Invoke(new Action(delegate
    {
    lblProcess.Text = "数据库文件记录读取完成,共" + dt.Rows.Count + "个,开始执行复制...";
    //读取完成后,开始copy file
    int taskCount = dt.Rows.Count;
    this.pgbWrite.Maximum = taskCount;
    this.pgbWrite.Value = 0;

    UpdateUIDelegate += UpdataUIStatus;//绑定更新任务状态的委托
    TaskCallBack += Accomplish;//绑定完成任务要调用的委托

    Thread thread = new Thread(Write);
    thread.IsBackground = true;
    thread.Start();
    }));
    });


    }

    private void AddDr(string sql)
    {
    SqlConnection con = new SqlConnection(string.Format("server={0};database={1};user={2};pwd={3};", txtServer.Text, txtDB.Text, txtSa.Text, txtPwd.Text));
    try
    {
    SqlCommand cm = con.CreateCommand();
    cm.CommandText = sql;
    con.Open();
    SqlDataReader dq = cm.ExecuteReader();
    if (dq.HasRows)
    {
    while (dq.Read())
    {
    if (dq[0] != DBNull.Value && dq[0].ToString() != "")
    {
    DataRow dataRow = dt.NewRow();
    dataRow["filepath"] = dq[0].ToString();
    dt.Rows.Add(dataRow);
    }
    }
    }
    }
    catch (Exception ex)
    {
    MessageBox.Show(ex.Message);
    }
    finally
    {
    con.Close();//使用完之后关闭数据库连接
    }
    }

    private void UpdataUIStatus(int step)
    {
    if (InvokeRequired)
    {
    this.Invoke(new AsynUpdateUI(delegate(int s)
    {
    this.pgbWrite.Value += s;
    this.lblProcess.Text = "共" + dt.Rows.Count + "个,正在执行第" + this.pgbWrite.Value.ToString() + "个";
    }), step);
    }
    else
    {
    this.pgbWrite.Value += step;
    this.lblProcess.Text = "共" + dt.Rows.Count + "个,正在执行第" + this.pgbWrite.Value.ToString() + "个";
    }
    }

    private void Accomplish()
    {
    //还可以进行其他的一些完任务完成之后的逻辑处理
    if (InvokeRequired)
    {
    this.Invoke(new AsynUpdateUI(delegate(int s)
    {
    lblProcess.Text = "执行完成,共" + dt.Rows.Count + "个," + success + "个成功," + fail + "个失败," + noFile + "个不存在";
    File.WriteAllLines(Application.StartupPath+"\\失败的文件记录.txt", failList);
    }), 0);
    }
    else
    {

    lblProcess.Text = "执行完成,共" + dt.Rows.Count + "个," + success + "个成功," + fail + "个失败," + noFile + "个不存在";
    File.WriteAllLines(Application.StartupPath + "\\失败的文件记录.txt", failList);
    }
    }

    public delegate void UpdateUI(int step);//声明一个更新主线程的委托
    public UpdateUI UpdateUIDelegate;

    public delegate void AccomplishTask();//声明一个在完成任务时通知主线程的委托
    public AccomplishTask TaskCallBack;
    private int success;
    private int fail;
    private int noFile;
    private List<string> failList;
    public void Write()
    {
    foreach (DataRow dr in dt.Rows)
    {
    string yFile = txtYFile.Text + "\\" + dr["filepath"].ToString();
    if (File.Exists(yFile))
    {
    string tFile = txtTFile.Text + "\\" + dr["filepath"].ToString();
    string outmsg;
    if (CopyFile(yFile, tFile, true, out outmsg))
    {
    success++;
    }
    else
    {
    failList.Add(yFile);
    fail++;
    }
    }
    else
    {
    noFile++;
    }

    //写入一条数据,调用更新主线程ui状态的委托
    UpdateUIDelegate(1);
    }
    //任务完成时通知主线程作出相应的处理
    TaskCallBack();
    //将更新包信息写入到客户端文件配置中
    Thread.Sleep(1000);
    }

    public static bool CopyFile(string sSource, string sTarget, bool bOverride, out string errorMessage)
    {
    errorMessage = null;

    try
    {
    if (!Directory.Exists(Path.GetDirectoryName(sTarget)))
    { // 如果目标路径不存在,则创建目标路径
    Directory.CreateDirectory(Path.GetDirectoryName(sTarget));
    }
    //如果目标文件已存在,先将其设为非只读
    SetFileReadOnly(sTarget, false);
    File.Copy(sSource, sTarget, bOverride);
    //保存后再次设为非只读
    SetFileReadOnly(sTarget, false);
    return true;
    }
    catch (Exception ex)
    {
    errorMessage = ex.Message;
    return false;
    }
    }

    public static bool SetFileReadOnly(string sPath, bool bReadOnly)
    {
    if (File.Exists(sPath) == false)
    {
    return false;
    }
    try
    {
    FileInfo fileInfo = new FileInfo(sPath);

    if (fileInfo.Attributes.ToString().IndexOf("ReadOnly") != -1)

    fileInfo.Attributes = bReadOnly ? FileAttributes.ReadOnly : FileAttributes.Normal;
    }
    catch (Exception ex)
    {
    return false;
    }

    return true;

    }

    }
    }

  • 相关阅读:
    ssh登录 The authenticity of host 192.168.0.xxx can't be established. 的问题
    linux系统之间互传文件
    Ubuntu16.04上Docker的安装及基本用法
    Ubuntu git 与 gitlab 关联
    Ubuntu E: Sub-process /usr/bin/dpkg returned an error code (1)
    ubuntu16.04搭建jdk1.8运行环境
    Ubuntu18.04 安装Tomcat 8.5
    VMware Ubuntu安装详细过程
    Ubuntu 14.04远程登录服务器--ssh的安装和配置
    Java中文编程开发,让Java编写更改复杂
  • 原文地址:https://www.cnblogs.com/lihaishu/p/16083672.html
Copyright © 2020-2023  润新知