在特定时间毫秒运行任务

问题描述

我需要在特定时间(毫秒)运行多个任务或线程。 我想在定义的时间将数据从程序发送到服务器。 我使用Rest Sharp发送数据。我想将数据发送到服务器的时间例如:5:46:50.100毫秒,5:46:50.150、5:46:50.200到30次(相差50毫秒)。 我使用以下代码执行此操作,但是“发送”功能无法按时执行。 当然,考虑到ping延迟,此时间将添加到ping延迟率,在其他时间也是如此。 另外,我不希望线程或其他任务等待先前的任务执行并在指定的时间准确执行,例如,以5:46:50.200运行的线程或任务不等待线程或任务在5:46:50.100的时间运行

private System.Threading.Timer timer;
private void SetUpTimer(TimeSpan alertTime)
{
    DateTime current = DateTime.Now;
    TimeSpan timetoGo = alertTime - current.TimeOfDay;
    if (timetoGo < TimeSpan.Zero)
    {
        return;
    }
    this.timer = new System.Threading.Timer(x =>
    {
        this.Send();
    },null,timetoGo,Timeout.InfiniteTimeSpan);
}

private void Send()
{
    Invoke(new Action(() =>
    {
        dataGridView1.Rows.Add("",DateTime.Now.ToString("hh:mm:ss.fff"),"","");
    }));
    /*IList<string> startTime = new List<string>();
    startTime.Add(DateTime.Now.ToString("hh:mm:ss.fff"));
    var client = new RestClient("mysite.com");
    var request = new RestRequest("/api",Method.POST,DataFormat.Json);

    request.AddHeader("Content-Type","application/json");
    client.UserAgent = "Mozilla / 5.0(Windows NT 10.0; Win64; x64; rv: 79.0) Gecko / 20100101 Firefox / 79.0";
    
    IRestResponse response = client.Execute(request);
    var content = response.Content;
    /*Invoke(new Action(() =>
    {
        dataGridView1.Rows.Add("",content,"");
    }));*/
    /*IList<string> contentList = new List<string>();
    contentList.Add(response.Content);
    IList<string> endTime = new List<string>();
    endTime.Add(DateTime.Now.ToString("hh:mm:ss.fff"));
    for (int i = 0; i < startTime.Count; i++)
    {
        Invoke(new Action(() =>
        {
            dataGridView1.Rows.Add("",startTime.ElementAt(i),contentList.ElementAt(i),endTime.ElementAt(i));
        }));
    }*/

}
private void button1_Click(object sender,EventArgs e)
{
    int mili = Convert.ToInt32(txtMili.Text);
    int dist = Convert.ToInt32(txtdistance.Text);
    int sec = Convert.ToInt32(txtSec.Text);
    for (int i=0; i < Convert.ToInt32(txtCount.Text); i++)
    {
        SetUpTimer(new TimeSpan(0,Convert.ToInt32(txtHour.Text),Convert.ToInt32(txtMin.Text),sec,mili));
        //mili = (mili + dist < 1000) ? mili + dist : (mili + dist) - 1000;
        mili = mili + dist;
        if (mili > 1000)
        {
            mili = mili - 1000;
            sec = sec + 1;
        }
        
    }
    button1.Enabled = false;
}

但是执行代码后获得的结果如下

enter image description here

解决方法

您将很难解决的问题列表(与完整列表相去甚远):

  • 对于每个Web请求,在请求实际“离开”客户端之前,需要进行一些设置。
  • 您仅具有一定数量的资源(CPU,I / O),如果每个请求完成的时间长于每个请求之间的时间,则该资源会限制您同时可以执行的操作量。在客户端和服务器端都是如此。
  • 您所在的网络可能运行缓慢,暂时瘫痪或网络堆栈中的其他因素正在延迟请求。同样在服务器端和客户端。
  • 也许最重要的是:默认情况下,永远不能保证客户端和服务器上的时钟完全同步-尤其是不能精确到毫秒。因此,即使您花费不到1毫秒的时间将请求从客户端发送到服务器,它们的时间戳也会不同。正如@chux所提到的,PTP之类的协议可以最大程度地减少差异,但这需要一些额外的设置。

因此,除非您找到一种方法来神奇地避免所有这些问题(其中许多您无法控制),否则您尝试做的事情几乎是不可能的。


更新用于调试代码:

请尝试将以下内容用作您的Send函数:

private void Send()
{
    var startTime = DateTime.Now;
    var client = new RestClient("mysite.com");
    var request = new RestRequest("/api",Method.POST,DataFormat.Json);

    request.AddHeader("Content-Type","application/json");
    client.UserAgent = "Mozilla / 5.0(Windows NT 10.0; Win64; x64; rv: 79.0) Gecko / 20100101 Firefox / 79.0";
    
    IRestResponse response = client.Execute(request);
    var requestEndTime = DateTime.Now;
    var content = response.Content;
    Invoke(new Action(() =>
    {
        // This lambda function "() => {...}" is called asynchronously,which
        // means that calling "DateTime.Now" in here will give you a wrong
        // timestamp,so you need to save those timestamps earlier like this

        dataGridView1.Rows.Add(
            "",startTime.ToString("hh:mm:ss.fff"),content,requestEndTime.ToString("hh:mm:ss.fff"));
    }));
}

请使用上述功能运行您的代码,并更新您的问题以显示最新结果。您仍然看到错误的开始时间戳吗?